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)
Related
I have the following while loop as part of my text justify function. The idea is that I have text strings (str) that need to be justified (spaces added to existing spaces in between words) to equal to a given length (len)
The catch is I can only add one space to an existing space at a time before I iterate over to the next space in the string and add another space there. If that's it for all spaces in the string and it's still not at the required length, I cycle back over to the original space (now two spaces) and add another. Then it goes to the next space between words and so on and so on. The idea is that any spaces between words in the string should not have a differential of more than one space (i.e. Lorem---ipsum--dolor--sit, not Lorem----ipsum--dolor-sit)
From my research, I decided that using a substring method off the original string to add that first extra space, then I will increment the index and move to the next space in the string and repeat the add. Here's my code:
var indexOf = str.indexOf(" ", 0);
if ( indexOf > -1 ) {
while ( indexOf > -1 && str.length < len ) {
//using a regexp to find a space before a character
var space = /\s(?=\b)/.exec(str);
str = str.substring(0, indexOf + 1) + " " + str.substring(indexOf + 1);
//go to next space in string
indexOf = str.indexOf(space, indexOf + 2);
if ( indexOf === -1 ) {
//loops back to beginning of string
indexOf = str.indexOf(space, 0);
}
}
}
finalResults.push(str);
This code works most of the time, but I noticed that there are instances where the cycle of spacing is not correct. For example, it generates the following string:
sit----amet,--blandit
when the correct iteration would be
sit---amet,---blandit
Any assistance in making this code properly iterate over every space (to add one space) in the string once, then cycling back around to the beginning of the string to start over until the desired length is achieved would be most appreciated.
I think it's more efficient to compute the number spaces required in the beginning.
var s = "today is a friday";
var totalLength = 40;
var tokens = s.split(/\s+/);
var noSpaceLength = s.replace(/\s+/g,'').length;
var minSpace = Math.floor((totalLength - noSpaceLength)/(tokens.length-1));
var remainder = (totalLength - noSpaceLength) % (tokens.length-1);
var out = tokens[0];
for (var i = 1; i < tokens.length; i++) {
var spaces = (i <= remainder ? minSpace+1 : minSpace);
out += "-".repeat(spaces) + tokens[i];
}
$('#out').text(out);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="out"></div>
This solution
splits the string (s) into words in an array (a)
finds the number of spaces to be added between all words (add)
finds the remainder of spaces to be added between first words (rem)
then sticks the words with add spaces + one if rem is not exhausted
Code
var s = "Caballo sin Nombre"; // assume one space between words
var len = 21; // desired length
var need = len - s.length;
var a = s.split(/ /); // split s
// need>0 and at least two words
if (need > 0 && a.length>1) {
var add = Math.floor(need / (a.length-1)) + 1; // all spaces need that (+existing)
var rem = need % (a.length-1); // remainder
var sp = '';
while (add-- > 0) sp += ' ';
// replace
var i,res = ''; // result
for (i=0 ; i<a.length-1 ; i++) {
res += a[i] + sp;
if (rem-- > 0) res += ' '; // remainder
}
res += a[i];
s = res;
}
console.log("'" + s + "' is " + s.length + " chars long.");
This function adds the spaces using a global replace, carefully limiting the text size.
function expand (txt, colwidth) {
txt = txt.replace (/\s\s+/, ' '); // Ensure no multiple spaces in txt
for (var spaces = ' ', // Spaces to check for
limit = colwidth - txt.length; // number of additional spaces required
limit > 0; // do while limit is positive
spaces += ' ') // add 1 to spaces to search for
txt = txt.replace (RegExp (spaces, 'g'),
function (r) {
// If limit > 0 then add a space else do not.
return limit > 0 && --limit ? r + ' ' : r
});
return txt;
}
for (var w = 21; w--;) console.log (expand ('this is a test.', w));
Shows this on console:
this is a test.
this is a test.
this is a test.
this is a test.
14 this is a test.
I'm working on a markdown to html parser. I understand this is a big project and there are third party libraries, but none the less I want to roll a simple solution on my own that doesn't have to handle every single aspect of markdown.
So far the process is to take an input (in my case the value of a textarea) and parse it line by line.
var html = [];
var lines = txt.split('\n'); //Convert string to array
//Remove empty lines
for(var index = lines.length-1; index >= 0; index--) {
if(lines[index] == '') lines.splice(index, 1);
}
//Parse line by line
for(var index = 0; index <= lines.length-1; index++) {
var str = lines[index];
if(str.match(/^#[^#]/)) {
//Header
str = str.replace(/#(.*?)$/g, '<h1>$1</h1>');
} else if(str.match(/^##[^#]/)) {
//Header 2
str = str.replace(/##(.*?)$/g, '<h2>$1</h2>');
} else if(str.match(/^###[^#]/)) {
//Header 3
str = str.replace(/###(.*?)$/g, '<h3>$1</h3>');
} else if(str.trim().startsWith('+')) {
//Unordered List
var orig = str;
str = str.replace(/\+(.*?)$/, '<li>$1</li>');
var previous, next;
if(index > 0) previous = lines[index-1];
if(!previous || previous && previous.indexOf('+') < orig.indexOf('+')) {
str = '<ul>' + str;
}
if(index < lines.length-1) next = lines[index+1];
if(!next || next && next.indexOf('+') < orig.indexOf('+')) {
var count = Math.max(0, orig.indexOf('+') / 4);
if(next) count = count - Math.max(0, next.indexOf('+') / 4);
for(var i=1; i<=count; i++) {
str = str + '</ul>';
}
}
if(next && next.trim().indexOf('+') == -1) str = str + '</ul>';
} else if(str.match(/^[0-9a-zA-Z]/)) {
//Paragraph
str = str.replace(/^([0-9a-zA-Z].*?)$/g, '<p>$1</p>');
}
//Inline formatting
str = str.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>'); //Bold
str = str.replace(/\_\_(.*?)\_\_/g, '<strong>$1</strong>'); //Another bold
str = str.replace(/\*(.*?)\*/g, '<em>$1</em>'); //Italics
str = str.replace(/\_(.*?)\_/g, '<em>$1</em>'); //Another italics
//Append formatted to return string
html.push(str);
}
Where I run into problems is with nested blocks such as ul. Currently the code looks at a line that starts with a + and wraps it in an li. Great, but these list items never get placed within a ul. I could run through the output again after the line by line and just wrap every group of li's, but that screws me up when I have nested li's that require their own ul.
Any thoughts on how to apply these additional wrapper tags? I've considered using my own special characters around list type elements so I know where to add the wrapper tags, but that breaks traditional markdown. I wouldn't be able to pass the raw markdown to someone other than myself and know they'd understand what was going on.
Edit I updated my code sample to include a working sample. The working sample also supports nested lists.
You need a very simple state machine.
When you encounter the first + you add <ul> and raise a flag.
If you don't see a line that starts with + and your flag is raised, then close the </ul>
I'm doing some Javascript to cut strings into 140 characters, without breaking words and stuff, but now i want the text so have some sense. so i would like if you find a character (just like ., , :, ;, etc) and if the string is>110 characters and <140 then slice it, so the text has more sense. Here is what i have done:
where texto means text, longitud means length, and arrayDeTextos means ArrayText.
Thank you.
//function to cut strings
function textToCut(texto, longitud){
if(texto.length<longitud) return texto;
else {
var cortado=texto.substring(0,longitud).split(' ');
texto='';
for(key in cortado){
if(key<(cortado.length-1)){
texto+=cortado[key]+' ';
if(texto.length>110 && texto.length<140) {
alert(texto);
}
}
}
}
return texto;
}
function textToCutArray(texto, longitud){
var arrayDeTextos=[];
var i=-1;
do{
i++;
arrayDeTextos.push(textToCut(texto, longitud));
texto=texto.replace(arrayDeTextos[i],'');
}while(arrayDeTextos[i].length!=0)
arrayDeTextos.push(texto);
for(key in arrayDeTextos){
if(arrayDeTextos[key].length==0){
delete arrayDeTextos[key];
}
}
return arrayDeTextos;
}
Break the string into sentences, then check the length of the final string before appending each sentence.
var str = "Test Sentence. Test Sentence";
var arr = str.split(/[.,;:]/) //create an array of sentences delimited by .,;:
var final_str = ''
for (var s in arr) {
if (final_str.length == 0) {
final_str += arr[s];
} else if (final_str.length + s.length < 140) {
final_str += arr[s];
}
}
alert(final_str); // should have as many full sentences as possible less than 140 characters.
I think Martin Konecny's solution doesn't work well because it excludes the delimiter and so removes lots of sense from the text.
This is my solution:
var arrTextChunks = text.split(/([,:\?!.;])/g),
finalText = "",
finalTextLength = 0;
for(var i = 0; i < arrTextChunks.length; i += 2) {
if(finalTextLength + arrTextChunks[i].length + 1 < 140) {
finalText += arrTextChunks[i] + arrTextChunks[i + 1];
finalTextLength += arrTextChunks[i].length;
} else if(finalTextLength > 110) {
break;
}
}
http://jsfiddle.net/Whre/3or7j50q/3/
I'm aware of the fact that the i += 2 part does only make sense for "common" usages of punctuation (a single dot, colon etc.) and nothing like "hi!!!?!?1!1!".
Should be a bit more effective without regex splits.
var truncate = function (str, maxLen, delims) {
str = str.substring(0, maxLen);
return str.substring(0, Math.max.apply(null, delims.map(function (s) {
return str.lastIndexOf(s);
})));
};
Try this regex, you can see how it works here: http://regexper.com/#%5E(%5Cr%5Cn%7C.)%7B1%2C140%7D%5Cb
str.match(/^(\r\n|.){1,140}\b/g).join('')
I'm in a situation where I'd like to take a string and split it in half, respecting words so that this string here doesn't get split into this str ing here, rather it would be split into this string here.
I figure a starting step would to be to split the string into an array based on spaces, then calculate length based on those pieces, but in my attempts longer strings end up being split up incorrectly.
Look for the first space before and after the middle, and pick the one closest to the middle.
Example:
var s = "This is a long string";
var middle = Math.floor(s.length / 2);
var before = s.lastIndexOf(' ', middle);
var after = s.indexOf(' ', middle + 1);
if (middle - before < after - middle) {
middle = before;
} else {
middle = after;
}
var s1 = s.substr(0, middle);
var s2 = s.substr(middle + 1);
Demo: http://jsfiddle.net/7RNBu/
(This code assumes that there actually are spaces on both sides of the middle. You would also add checks for before and after being -1.)
Edit:
The check that I talked about in the node would be done correctly like this:
if (before == -1 || (after != -1 && middle - before >= after - middle)) {
middle = after;
} else {
middle = before;
}
Here is a fiddle where you can edit the text and see the result immediately: http://jsfiddle.net/Guffa/7RNBu/11/
I wanted to leave this as a comment but do not have enough rep points. The top solution right now fails pretty easily because it does not check for "-1" when using the indexOf method. See this fiddle:
http://jsfiddle.net/7RNBu/7/
var s = "This is a long strinjjjjjjjjjjjjjjjjg";
var middle = Math.floor(s.length / 2);
var before = s.lastIndexOf(' ', middle);
var after = s.indexOf(' ', middle + 1);
if (middle - before < after - middle) {
middle = before;
} else {
middle = after;
}
var s1 = s.substr(0, middle);
var s2 = s.substr(middle + 1);
You might also care about newlines, tabs, as well as spaces, so I would use a regex like this:
var s = "this string here";
var idx = s.length / 2;
while (idx < s.length && s[idx].match(/\s/) == null)
idx++;
var s1 = s.substring(0, idx);
var s2 = s.substring(idx);
document.getElementById("s1").innerText = s1;
document.getElementById("s2").innerText = s2;
See this fiddle: http://jsfiddle.net/nS6Bj/5/
let str = 'qwerty';
let half = Math.floor(str.length / 2);
str = str.slice(0, half) + ' ' + str.slice(half, str.length);
//output
'qwe rty'
I first thought I had an off-by-one error, but I eventually worked through it. Here's a working example.
Now to break down the logic used:
var calculate = function(initialString) {
var halfwayPoint = Math.floor(initialString.length / 2);
var strArray = initialString.split(' ');
// Caluclate halfway point, then break string into words
var wordFlag; // Will be split point
var charCount = 0;
_.each( strArray, function(word, strArrayIndex) {
if (wordFlag) return false;
// If we have the location, exit
// If charCount is before the halfway point
// and the end of word is after halfway point
// Then set the flag
// We add strArrayIndex to the word length to include spaces
if (charCount <= halfwayPoint &&
((charCount + word.length + strArrayIndex) >= halfwayPoint) ) {
wordFlag = strArrayIndex;
return false;
}
// Increase charCount to be length at the end of this word
charCount += (word.length);
});
if (!wordFlag) return null;
// Split the word array by the flag we figured out earlier
var lineOneArray = strArray.slice(0, (wordFlag + 1));
var lineTwoArray = strArray.slice(wordFlag + 1);
// We now join the word arrays into a string, stripping beginning and ending spaces.
var stOne = (lineOneArray.join(' ')).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var stTwo = (lineTwoArray.join(' ')).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
// Finally return the split strings as an array.
return [stOne, stTwo];
};
If anyone sees holes in my logic, let me know! I'm pretty sure this works in most cases though.
If you'd like the second string to be longer than the first, (ie have the line break before rather than after the middle word), then don't add +1 to wordFlag.
This will split your string based on word count (not character count, so the exact length of each half could be quite different, depending on the placement of long & short words).
var s = "This is a string of filler text";
var pieces = s.split(" "),
firstHalfLength = Math.round(pieces.length/2),
str1 = "",
str2 = "";
for (var i = 0; i < firstHalfLength; i++){
str1 += (i!=0?" ":"") + pieces[i];
}
for (var i = firstHalfLength; i < pieces.length; i++){
str2 += (i!=firstHalfLength?" ":"") + pieces[i];
}
document.write(s);
document.write("<br />"+str1);
document.write("<br />"+str2);
// Output
This is a string of filler text
This is a string
of filler text
http://jsfiddle.net/daCrosby/7RNBu/2/
<h1>
<span>
// for first half start from 0 till middle
{title.substring(0, title.length / 2)}
</span>
<span>
// second half just point the starting point
{title.substring(title.length / 2)}
</span>
</h1>
I am trying to highlight parentheses depending on their level and if they are matched or not. So first level gets the following class paren_1, second gets paren_2 and so on. I want to highlight the set of parentheses next to the caret too, if there are any. Meaning if you have the caret next to a parenthesis (openeing or closing) it should highlight said parenthesis and its corresponding one. My (broken) implementation of this is shown in the fiddle.
This works fairly well. Problems are the following
If there is HTML in the input string, everything breaks apart. I tried escaping the html before sending it in using jQuery('<div />').text(text).html(), which works, but ruins the caret position.
If there are several parentheses on the "same level" and the caret is next to one set, it highlights more than it should.
If there is an unmatched parenthesis, it should be highlighted in red or something similar. This is not working either and I have no idea how to implement it. I have tried my best but everything has failed.
JSFiddle: http://jsfiddle.net/yWzWV/1/
Note to you all: I am in no way very good with either javascript or jquery, so you'll have to excuse me if this code makes your eyes bleed.
Thanks in advance!
Problem is solved, but I've encountered another. Here's the fiddle with the fixes: http://jsfiddle.net/Axvgf/
Here's the changed method:
function colorize(text, pos) {
var i = 0, current_times = 0;
var startc = '(', endc = ')';
var current = -1;
var entities = {'>': '>','<':'<'};
var p2 = 0;
var regex = new RegExp(Object.keys(entities).join("|"),'g');
var converted = text.replace(regex, function(x, j) {
if(pos > j) p2 += entities[x].length - 1;
return entities[x];
});
pos += p2;
var parens = [], indices = [], o = {};
var newText = converted.replace(/((?:\\)*)([()])/g, function(full, escape, x, idx) {
var len = escape.split(/\\/g).length - 1;
if (len % 2 == 0) {
indices.push(idx);
if (x == startc) ++i;
o[idx] = { selected: false, type: x, depth: i, idx: idx, pair: -1, extra: escape };
if (idx == pos) o[idx].selected = true;
if (x == startc) parens.push(idx);
else {
if (parens.length > 0) {
var p = parens.pop();
o[idx].pair = p;
if (o[p].selected) o[idx].selected = true;
o[p].pair = idx;
if (o[idx].selected) o[p].selected = true;
}
--i
}
}
});
newtext = converted;
indices = indices.sort(function(x,y) { return Number(y) - Number(x); });
indices.forEach(function(i) {
newtext = newtext.substr(0,i) + o[i].extra +
"<span class='" + (o[i].pair == -1 ? "unmatched " : "paren_" + (o[i].depth % 5)) +
(o[i].selected ? " selected_paren": "") + "'>" + o[i].type + "</span>" +
newtext.substr(i + 1 + o[i].extra.length)
});
return newtext;
}