Javascript to reduce line breaks to two? - javascript

I'm using the following javascript:
if (theSelection)
{
for (var i = 0, l = theSelection.length; i < l; i++)
{
if (theSelection[i] == '[' && theSelection[i+1] == 'q') level++;
if (theSelection[i-6] == 'q' && theSelection[i-7] == '/' && theSelection[i-8] == '[') level--;
if (level<1) tmp.push(theSelection[i]);
}
theSelection = tmp.join('');
}
... to remove nested quotes from text before it is sent to a reply box, but it leaves behind line breaks in place of the purged nested quotes. So, for instance, if I quote a post from User 1 which says...
Text.
[quote="User 2"]Quote text.[/quote]
More text.
It shows up in the reply box as...
[quote="User 1"]Text.
More text.[/quote]
What would I add to this javascript to either remove this space or limit the space between new lines to just two line breaks, so that the final text displayed in the reply box appears as:
[quote="User 1"]Text.
More text.[/quote]
Thanks for any help.
EDIT:
Here's a larger bit of the code:
if (theSelection)
{
for (var i = 0, l = theSelection.length; i < l; i++)
{
if (theSelection[i] == '[' && theSelection[i+1] == 'q') level++;
if (theSelection[i-6] == 'q' && theSelection[i-7] == '/' && theSelection[i-8] == '[') level--;
if (level<1) tmp.push(theSelection[i]);
}
theSelection = tmp.join('');
}
if (theSelection)
{
if (bbcodeEnabled)
{
insert_text('[quote="' + username + '"]' + '\n' + '\n' + theSelection + '[/quote]' + '\n' + '\n');
}
else
{
insert_text(username + ' ' + l_wrote + ':' + '\n');
var lines = split_lines(theSelection);
for (i = 0; i < lines.length; i++)
{
insert_text('> ' + lines[i] + '\n');
}
}
}
I placed...
if (theSelection)
{
theSelection = theSelection.replace(/\n{2,}/g, "\n\n");
}
... between the two existing "if (theSelection)" statements, and it worked great. One remaining issue though. The nested quote removal happens before the quoted text is placed within its own quote tags, and two line breaks are added after the opening quote tag. So if a quoted post contained a nested quote before any original text, then the text that the above code generates has four line breaks at the opening instead of the intended two. So I think I would need to place...
if (theSelection)
{
theSelection = theSelection.replace(/\n{2,}/g, "\n\n");
}
... after theSelection is inserted within its own quote tags, at which point "if (theSelection)" seems to no longer work, and I'm so new to javascript that I don't know how to replace "theSelection" with something that will reflect the output of the previous "if (theSelection)" statement. I hope that made at least a little sense.

Use a RegExp. The following code will replace 2+ new lines by two newlines.
string = string.replace(/\n{2,}/g, "\n\n")
I recommend to show a sign that notifies the reader of the fact that a quote has disappeared. Consider the following:
Post 50 by userA: My fish died =(
============================
Post 51 by userB:
[quote=Niceidea]
(2 pages ago) What about blabla. ...
[/quote]
Awesome!
============================
After applying your code:
============================
Post 50 by userA: My fish died =(
============================
Post 51 by userB: Awesome!
============================
The previous poster might be offended, because he didn't know the context of the reply.

I have figured out a nice solution: less code and exactly the thing you wanted:
var output,
theSelection = 'Text.\n\n[quote="User 2"]\nQuote tex\nt.\n[/quote]\n\n\n\n\nMore text.';
/*
* theSelection is:
* 'Text.
*
* [quote="User 2"]
* Quote tex
* t.
* [/quote]
*
*
*
* More text.'
*/
if (theSelection) {
output = theSelection.replace(/\[quote=".*"\][\s\S]*\[\/quote\]/gi, '')
.replace(/\n{2,}/g, '\n\n');
}
console.log(output);
/*
* Outputs:
* 'Text.
*
* More text.'
*
*/

Related

Trying to find substring of string that equals "\" in javascript

What I'm trying to do is compare the order of backslashes in 2 texts (one is English text, the other is user inputted translated text).
I first do an if statement to make sure both texts have backslashes and then create separate lists for the two texts in order to compare the order.
NOTE: if sourcetext has a backslash, in dev tools, it does show as "\".
But even though I know there's a backslash at a specific index, my code isn't placing that sourcetext.substring(w+1, 1) into my tokenlist...
Not sure where to fix my bug and/or why it's not recognizing the comparison of the substring and "\".
The output I want from the tokenlist is:
tokenlist = "\\n\\n\\t";
But instead I get nothing put into tokenlist.
Any insight would be appreciated!
var sourcetext = "Example \n\t\n";
var newtext = "Exemple \n\t\n";
if (newtext.includes('\\') && sourcetext.includes('\\')) {
var tokenlist = "";
var tokenlisttran = "";
for (let w = 0; w < sourcetext.length - 1; w++) {
if (sourcetext.substring(w, 1) == "\\") {
tokenlist += "\\" + sourcetext.substring(w + 1, 1);
}
}
for (let i = 0; i < newtext.length - 1; i++) {
if (newtext.substring(i, 1) == "\\") {
tokenlisttran += "\\" + newtext.substring(i + 1, 1);
}
}
}
console.log(tokenlist,tokenlisttran)

Displaying current & total page number N(N)

I am new to Javascript,so forgive my silly mistakes in advance.
I have a requirement where I have to print current and total page number excluding even pages which are blank.
Example : For 5 page long document,it should display like:
1(3)
2(3)
3(3)
Any sort of info is welcome since I am in dire need of this code to work.
I have tried this but it doesn't work:
var current_page=0 ;
var total_pages=0;
if((current_page<total_pages)||(current_page=total_pages))
{
current_page++;
if(current_page % 2!==0)
{
total_pages++;
}
}
Also, this one too doesn't worked :(
var temp = (this.pageNum) + "(" + (this.numPages) + ")" ;
You have a logical error here:
current_page = total_pages // Note single = symbol between.
You are assigning instead of comparing. Please use == to compare:
current_page == total_pages
Or === for strict comparison as the type of both the variables is same.
Does that help?
function (totalPages, currentPage)
{
if (currentPage%2==1) return "";
var tp = parseInt(totalPages/2+1);
var cp = parseInt(currentPage/2+1);
return "" + cp + "(" + tp + ")";
}

Pretty print JSON preserve property order

I've read several posts on using JSON.stringify to pretty print a JSON string with Javascript. However, it seems to re-order the nodes. I would like to have a formatted JSON object in the same order as the string provided.
Here's an example of what I get using the prescribed methods
var sJson = '{"2":"stuff", "1":"care"}';
alert(JSON.stringify(JSON.parse(sJson), null, 2));
Result:
{
"1": "care",
"2": "stuff"
}
Desired Result:
{
"2": "stuff",
"1": "care"
}
I'm happy to use an external library if JSON.stringify is unable to do this. Note: I'm starting with a minified JSON string from the server.
Because in JavaScript Objects are not ordered, properties in an Object do not preserve order. In order to keep your order you would need to change your JSON to use an array instead: [{"2":"stuff"}, {"1":"care"}].
We had a similar question regarding JSON formatting for a display. A couple of robust solutions are available:
The 'json-order' package offers parsing, formatting & pretty-printing with stable ordering. This is based on having ordered input.
The 'fast-json-stable-stringify' package offers deterministic formatting based on sorting.
My quick testing with Chrome also found that JSON.parse() seemed to preserve order; this covers much of the browser market (Chrome, Edge, etc) but is not guaranteed on other browsers. This may offer a cheap partial solution, but is not fully robust.
I was able to port the php function I found on this page; it's working like a champ.
function pad(width, string, padding) {
return (width <= string.length) ? string : pad(width, padding + string, padding)
}
function json_pretty(json, html)
{
var
out = '',
nl = "\n",
cnt = 0,
tab = 4,
len = json.length,
space = ' ';
if(html == true) {
space = ' ';
nl = '<br/>';
}
k = space.length ? space.length : 1;
for (i=0; i<=len; i++) {
char = json.substring(i, i+1);
if(char == '}' || char == ']') {
cnt--;
out += nl + '' + pad(tab * cnt * k, '', space);
}
else if(char == '{' || char == '[') {
cnt++;
}
out += char;
if(char == ',' || char == '{' || char == '[') {
out += nl + pad(tab * cnt * k, '', space);
}
if(char == ':') {
out += ' ';
}
}
return out;
}

Rendering Plaintext as HTML maintaining whitespace – without <pre>

Given any arbitrary text file full of printable characters, how can this be converted to HTML that would be rendered exactly the same (with the following requirements)?
Does not rely on any but the default HTML whitespace rules
No <pre> tag
No CSS white-space rules
<p> tags are fine, but not required (<br />s and/or <div>s are fine)
Whitespace is maintained exactly.
Given the following lines of input (ignore erroneous auto syntax highlighting):
Line one
Line two, indented four spaces
A browser should render the output exactly the same, maintaining the indentation of the second line and the gap between "indented" and "spaces". Of course, I am not actually looking for monospaced output, and the font is orthogonal to the algorithm/markup.
Given the two lines as a complete input file, example correct output would be:
Line one<br /> Line two,
indented four spaces
Soft wrapping in the browser is desirable. That is, the resulting HTML should not force the user to scroll, even when input lines are wider than their viewport (assuming individual words are still narrowing than said viewport).
I’m looking for fully defined algorithm. Bonus points for implementation in python or javascript.
(Please do not just answer that I should be using <pre> tags or a CSS white-space rule, as my requirements render those options untenable. Please also don’t post untested and/or naïve suggestions such as “replace all spaces with .” After all, I’m positive a solution is technically possible — it’s an interesting problem, don’t you think?)
The solution to do that while still allowing the browser to wrap long lines is to replace each sequence of two spaces with a space and a non break space.
The browser will correctly render all spaces (normal and non break ones), while still wrapping long lines (due to normal spaces).
Javascript:
text = html_escape(text); // dummy function
text = text.replace(/\t/g, ' ')
.replace(/ /g, ' ')
.replace(/ /g, ' ') // second pass
// handles odd number of spaces, where we
// end up with " " + " " + " "
.replace(/\r\n|\n|\r/g, '<br />');
Use a zero-width space (​) to preserve whitespace and allow the text to wrap. The basic idea is to pair each space or sequence of spaces with a zero-width space. Then replace each space with a non-breaking space. You'll also want to encode html and add line breaks.
If you don't care about unicode characters, it's trivial. You can just use string.replace():
function textToHTML(text)
{
return ((text || "") + "") // make sure it is a string;
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\t/g, " ")
.replace(/ /g, "​ ​")
.replace(/\r\n|\r|\n/g, "<br />");
}
If it's ok for the white space to wrap, pair each space with a zero-width space as above. Otherwise, to keep white space together, pair each sequence of spaces with a zero-width space:
.replace(/ /g, " ")
.replace(/(( )+)/g, "​$1​")
To encode unicode characters, it's a little more complex. You need to iterate the string:
var charEncodings = {
"\t": " ",
" ": " ",
"&": "&",
"<": "<",
">": ">",
"\n": "<br />",
"\r": "<br />"
};
var space = /[\t ]/;
var noWidthSpace = "​";
function textToHTML(text)
{
text = (text || "") + ""; // make sure it is a string;
text = text.replace(/\r\n/g, "\n"); // avoid adding two <br /> tags
var html = "";
var lastChar = "";
for (var i in text)
{
var char = text[i];
var charCode = text.charCodeAt(i);
if (space.test(char) && !space.test(lastChar) && space.test(text[i + 1] || ""))
{
html += noWidthSpace;
}
html += char in charEncodings ? charEncodings[char] :
charCode > 127 ? "&#" + charCode + ";" : char;
lastChar = char;
}
return html;
}
Now, just a comment. Without using monospace fonts, you'll lose some formatting. Consider how these lines of text with a monospace font form columns:
ten seven spaces
eleven four spaces
Without the monospaced font, you will lose the columns:
ten seven spaces
eleven four spaces
It seems that the algorithm to fix that would be very complex.
While this doesn't quite meet all your requirements — for one thing it doesn't handle tabs, I've used the following gem, which adds a wordWrap() method to Javascript Strings, on a couple of occasions to do something similar to what you're describing — so it might be a good starting point to come up with something that also does the additional things you want.
//+ Jonas Raoni Soares Silva
//# http://jsfromhell.com/string/wordwrap [rev. #2]
// String.wordWrap(maxLength: Integer,
// [breakWith: String = "\n"],
// [cutType: Integer = 0]): String
//
// Returns an string with the extra characters/words "broken".
//
// maxLength maximum amount of characters per line
// breakWith string that will be added whenever one is needed to
// break the line
// cutType 0 = words longer than "maxLength" will not be broken
// 1 = words will be broken when needed
// 2 = any word that trespasses the limit will be broken
String.prototype.wordWrap = function(m, b, c){
var i, j, l, s, r;
if(m < 1)
return this;
for(i = -1, l = (r = this.split("\n")).length; ++i < l; r[i] += s)
for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : ""))
j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length
|| c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
return r.join("\n");
};
I'd also like to comment that it seems to me as though, in general, you'd want to use a monospaced font if tabs are involved because the width of words would vary with the proportional font used (making the results of using of tab stops very font dependent).
Update: Here's a slightly more readable version courtesy of an online javascript beautifier:
String.prototype.wordWrap = function(m, b, c) {
var i, j, l, s, r;
if (m < 1)
return this;
for (i = -1, l = (r = this.split("\n")).length; ++i < l; r[i] += s)
for (s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s =
s.slice(j)).length ? b : ""))
j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m :
j.input.length - j[0].length || c == 1 && m || j.input.length +
(j = s.slice(m).match(/^\S*/)).input.length;
return r.join("\n");
};
Is is very simple if you use jQuery library in your project.
Just one line ,Add asHTml extenstion to String Class and :
var plain='<a> i am text plain </a>'
plain.asHtml();
/* '<a> i am text plain </a>' */
DEMO :http://jsfiddle.net/abdennour/B6vGG/3/
Note : You will not have to access to DoM . Just use builder design pattern of jQuery $('<tagName />')

Converting VBScript to Javascript, What is the right way of parsing source code?

I was asked to convert some VB6/VBScript code to javascript so after googling it and not finding anything I can use,I wrote a small javascript function to help me do the conversion; it's so crude and only converts (some of) the synatx, but it worked for me for the job I had...now I'm thinking of improving it but the method I used is so primitive (Regular Expression matching and replacing).
So...my question is:
What is the proper way to parse source code? is there any (not so complicated) way of doing it? and I don't want to use Exe's, it must be done entirely in Javascript. I'm not searching for ready-to-use source code (I don't think it exists!) but I want to learn how to be able to start with source code and turn it into objects (the opposite of serialization, I think?).
//here is the code:
var strs=[];
function vbsTojs(vbs){
var s = vbs;
s = HideStrings(s);
//only function block
s = s.match(/Function[\w\W]+End\s+Function/gim)[0];
//line-continuation char
s = s.replace(/_\n/gm,"");
//replace ":" with CRLF
s = s.replace(/:/gm,"\n");
//move inline comment to its own line
s = s.replace(/^(.+)'(.*)$/gim,"'$2\n$1");
//single line if -> multiple line
s = s.replace(/\bthen\b[ \t](.+)/gi,"then\n$1\nEnd If");
//alert(s);
var Vars='';
var Fx='';
var FxHead='';
var Args = '';
a=s.split('\n');
//trim
for(i=0;i<a.length;i++){
a[i]=a[i].replace(/^\s+|\s+$/,"");
}
//remove empty items
a=a.filter(function(val) { return val !== ""; });
//alert(a.join('\n'));
//function
a[0]=a[0].replace(/function\s+/i,"");
Fx = a[0].match(/^\w+/)[0];
a[0]=a[0].replace(Fx,"").replace(/[\(\)]/g,"");
a[0]=a[0].replace(/\bbyval\b/gi,"").replace(/\bbyref\b/gi,"").replace(/\boptional\b/gi,"");
a[0]=a[0].replace(/\bas\s+\w+\b/gi,"");
a[0]=a[0].replace(/\s+/g,"");
a[0]=a[0].replace(/,/gi,", ");
FxHead = "function " + Fx+ " ("+ a[0] + "){";
a[0]="";
//end function
a.length = a.length-1;
for(i=1;i<a.length;i++){
//Vars
if(a[i].search(/^dim\s+/i)>-1){
a[i]=a[i].replace(/dim\s*/i,"");
Vars += a[i] + ",";
a[i]='';
//FOR
}else if(a[i].search(/^\bFOR\b\s+/i)>-1){
a[i]=a[i].replace(/^\bFOR\b\s+/i,"");
counter = a[i].match(/^\w+/)[0];
from = a[i].match(/=\s*[\w\(\)]+/)[0];
from=from.replace(/=/,"").replace(/\s+/g,"");
a[i]=a[i].replace(counter,"").replace(from,"").replace(/\bTO\b/i,"");
to = a[i].match(/\s*[\w\(\)]+\s*/)[0];
to=to.replace(/=/,"").replace(/\s+/g,"");
a[i] = "for(" + counter + "=" + from + "; " + counter + "<=" + to + "; " + counter + "++){"
//NEXT
}else if(a[i].search(/^NEXT\b/i)>-1){
a[i] = "}";
//EXIT FOR
}else if(a[i].search(/\bEXIT\b\s*\bFOR\b/i)>-1){
a[i] = "break";
//IF
}else if(a[i].search(/^\bIF\b\s+/i)>-1){
a[i]=a[i].replace(/^\bIF\b\s+/i,"");
a[i]=a[i].replace(/\bTHEN$\b/i,"");
a[i]=a[i].replace(/=/g,"==").replace(/<>/g,"!="); //TODO: it should not replace if inside a string! <---------------
a[i]=a[i].replace(/\bOR\b/gi,"||").replace(/\bAND\b/gi,"&&"); //TODO: it should not replace if inside a string! <---------------
a[i] = "if(" + a[i] + "){";
//ELSE
}else if(a[i].search(/^ELSE/i)>-1){
a[i] = "}else{";
//END IF
}else if(a[i].search(/^END\s*IF/i)>-1){
a[i] = "}";
//WHILE
}else if(a[i].search(/^WHILE\s/i)>-1){
a[i] = a[i].replace(/^WHILE(.+)/i,"while($1){");
//WEND
}else if(a[i].search(/^WEND/i)>-1){
a[i] = "}";
//DO WHILE
}else if(a[i].search(/^DO\s+WHILE\s/i)>-1){
a[i] = a[i].replace(/^DO\s+WHILE(.+)/i,"while($1){");
//LOOP
}else if(a[i].search(/^LOOP$/i)>-1){
a[i] = "}";
//EXIT FUNCTION
}else if(a[i].search(/\bEXIT\b\s*\bFUNCTION\b/i)>-1){
a[i] = "return";
//SELECT CASE
}else if(a[i].search(/^SELECT\s+CASE(.+$)/i)>-1){
a[i]=a[i].replace(/^SELECT\s+CASE(.+$)/i,"switch($1){");
}else if(a[i].search(/^END\s+SELECT/i)>-1){
a[i] = "}";
}else if(a[i].search(/^CASE\s+ELSE/i)>-1){
a[i] = "default:";
}else if(a[i].search(/^CASE[\w\W]+$/i)>-1){
a[i] = a[i] + ":" ;
}
//CONST
else if(a[i].search(/^CONST/i)>-1){
a[i] = a[i].replace(/^CONST/i,"const");
}
else{
//alert(a[i]);
}
//COMMENT
if(a[i].search(/^\'/)>-1){
a[i]=a[i].replace(/^\'/,"//");
}else if(a[i].search(/\'.*$/)>-1){
a[i]=a[i].replace(/\'(.*)$/,"//$1");
}
}
//alert(a.join("*"));
Vars = Vars.replace(/\s*AS\s+\w+\s*/gi,"");
if(Vars!="") Vars = "var " + Vars.replace(/,$/,";").replace(/,/g,", ");
FxHead + '\n' + Vars;
a=a.filter(function(val) { return val !== ""; }) //remove empty items
for(i=0;i<a.length;i++){
if (a[i].search(/[^}{:]$/)>-1) a[i]+=";";
}
ss = FxHead + '\n' + Vars + '\n' + a.join('\n') + '\n}';
ss = ss.replace(new RegExp(Fx+"\\s*=\\s*","gi"),"return ");
ss = UnHideStrings(ss);
return jsIndenter(ss);
}
//-----------------------------------------------------
function jsIndenter(js){
var a=js.split('\n');
var margin=0;
var s = '';
//trim
for(i=0;i<a.length;i++){ a[i]=a[i].replace(/^\s+|\s+$/,""); }
//remove empty items
a=a.filter(function(val) { return val !== ""; });
for(var i=1;i<a.length;i++){
if(a[i-1].indexOf("{")>-1) margin += 4 ;
if(a[i].indexOf("}")>-1) { margin -= 4; }
if(margin<0) margin = 0;
a[i] = StrFill(margin," ") + a[i] ;
}
return a.join('\n');
}
function StrFill(Count,StrToFill){
var objStr,idx;
if(StrToFill=="" || Count==0){
return "";
}
objStr="";
for(idx=1;idx<=Count;idx++){
objStr += StrToFill;
}
return objStr;
}
function HideStrings(text){
const x = String.fromCharCode(7);
const xxx = String.fromCharCode(8);
text = text.replace(/"""/gim, '"'+xxx); //hide 3 quotes " " "
var idx=0, f=0;
while(f>-1){
f = text.search(/".+?"/gim);
if(f>-1){
strs.push(text.match(/".+?"/)[0]);
//alert(strs[idx]);
text = text.replace(/".+?"/, x+idx+x);
idx++;
}
}
//alert(text);
return text;
}
function UnHideStrings(text){
for(var i=0; i<strs.length; i++){
text = text.replace(new RegExp("\\x07"+i+"\\x07"), strs[i]);
}
//Unhide 3 quotes " " " ***BUG: causes unterminated string if triple-quotes are at the end of the string
text = text.replace(/\x08/gim,'\\"');
text = text.replace(/""/gi,'\\"');
return text;
}
The proper way to parse source code for any programming language is to use a parser. Regular expressions are a useful part of (some) parsers, but a parser is a different sort of thing. There is quite a body of research and techniques in the Computer Science literature on the subject of parsing, and it's a fascinating pursuit to study.
"Converting" a bunch of Visual Basic code to Javascript is a project that seems inherently fraught with peril and mystery. A Visual Basic parser will be just the first significant hurdle to conquer. After that, you'll need to figure out how to semantically represent the Visual Basic operations in Javascript. Depending on the original context of the code, that could be somewhat weird. (You don't mention anything about where this code all runs.)
As enriching a learning experience as this might be, it's not unlikely that translating the code by hand will (in the end) take less time and produce better results. That's particularly true if you're just now finding out that there is such a thing as a "parser".
Nice job. Sounds like you did something that might not be perfect, but it did the job.
I'd recommend looking into parsers and grammars if you want to make it more sophisticated. There are lots of parser generators that would be able to help you. You'd have to come up with a grammar for the source language, generate the lexer/parser, and then use that to generate an abstract syntax tree (AST). Once you have that, you can walk the AST and ask it to emit any code you want.
It's doable but, as Oded says, it's not trivial.

Categories

Resources