Highlight parentheses inside input box - javascript

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;
}

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)

Get the next key from array from string with symbols

I'm working on a simple but difficult problem for me right now, I'm use to work in jQuery but need this to be done in Javascript.
So simple as it is, the user inputs a string lets say:
"hey, wanna hang today?". It should output the next character in my array, so it would be like this: "ifz, xboob iboh upebz?".
And I have tried everything I can come up with. Hopefully some of you guys see the problem right away.
I have set up a short jsFiddle that shows similar to what I got.
function gen() {
var str = document.getElementById('str').value,
output = document.getElementById('output');
var alph = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','æ','ø','å','a'];
for (var i=0;i<str.length;i++) {
var index = str[i].charAt(0),
e = alph.indexOf(index);
console.log(alph[e + 1]);
output.innerHTML += alph[e + 1];
}
}
If you only want to skip to next letter with those chars and leave the others like space and ? as they are:
var index = str[i].charAt(0),
e = alph.indexOf(index);
if(e == -1){
output.innerHTML += index;
}else{
output.innerHTML += alph[e + 1];
}
Update: using #David Thomas method, you could do the following: (wouldnt work for 'å' though)
var index= str[i].toLowerCase().charCodeAt(0);
if((index > 96 && index < 123)){ // a to z
output.innerHTML += String.fromCharCode(str[i].charCodeAt(0)+1);
}else{
output.innerHTML += str[i];
}
}
I'd personally recommend the following approach, which should work with any alphabet for which there's a Unicode representation and, somewhat importantly, doesn't require a hard-coded array of letters/punctuation for each language:
function gen() {
var str = document.getElementById('str').value,
strTo = '',
output = document.getElementById('output');
for (var i = 0; i < str.length; i++) {
strTo += String.fromCharCode(str[i].charCodeAt(0) + 1);
}
output.textContent = strTo;
}
// hey, wanna hang today? -> ifz-!xboob!iboh!upebz#
JS Fiddle demo.
References:
String.prototype.charCodeAt().
String.prototype.fromCharCode().
Why does gen(',') === 'a'?
var alph = 'abcdefghijklmnopqrstuvwxyz';
var e = alph.indexOf(',');
console.log(e);
// -1
console.log(alph[e + 1]);
// 'a'
You need to take this case into account; otherwise, any characters that aren't in alph will map to 'a'.
(I see that you've also duplicated 'a' at the start and end of alph. This works, though it's more common either to use the modulus operator % or to check explicitly if e === alph.length - 1.)
You just have to add an array with the non respected characters:
var ex = ['?','!',' ','%','$','&','/']
In whole
for (var i=0;i<str.length;i++) {
var index = str[i].charAt(0)
if (alph.indexOf(index) >-1) {
var e = alph.indexOf(index);
output.innerHTML += alph[e + 1];
} else {
var e = index;
output.innerHTML += e;
}
}
JSFIDDLE: http://jsfiddle.net/TRNCFRMCN/hs15f0kd/8/.

Each key value, join values inside loop

So i have a string, and I'm trying to join the content; if the val length is less than 10 chars, join it with the next value. But when i try this code, it joins with the same val instead of the next one.
//Set the regex.
myregex = /(<p>.*?<\/p>)/g;
//Variable string.
content = Example: <p>Hello</p><p>This is my test content</p><p>etc</p>
$(content.match(myregex)).each(function (key, val) {
var test = $(val).text();
if (test.length < 10) {
var n = val.concat(val);
$('#mydiv').append('<div>' + n + '</div>');
} else {
$('#mydiv').append('<div>' + val + '</div>');
}
})
This line here: val.concat(val), is indeed duplicating your content. What you need to do is grab the next value from the regex instead of the current one. Something like the following should work.
var matches = content.match(myregex),
myDiv = $('#mydiv');
for (var i = 0, len = matches.length; i < len; i++){
if (i + 1 < len && matches[i].length < 10){
myDiv.append('<div>' + matches[i].concat(matches[i+1]) + '</div>');
i += 1;
}
else myDiv.append('<div>' + matches[i] + '</div>');
}
val and val are the same thing, so of course val.concat(val) will duplicate it.
If you want to use $.each, I think it might be better to join with the previous value, because you don't know what the next one will be yet.
var previous = [];
$(content.match(myregex)).each(function (key, val) {
var test = $(val).text();
if (test.length < 10) {
previous = val;
} else {
if(previous.length) {
val = previous.concat(val);
}
$('#mydiv').append('<div>' + val + '</div>');
previous = [];
}
});

JavaScript - Need help with string manipulation

say you have:
var foo = "donut [$25]"
What would you need to do in order to delete everything between and including the [ ].
so you get: foo = "donut" after the code is run.
So far I have tried most of the solutions below, but they all either do nothing or crash.
Maybe it's something with my code, please see below:
$('select').change(function () { OnSuccess(mydata); });
function OnSuccess(data) {
var total = 0;
$('select').each(function () {
var sov = parseInt($(this).find('option:selected').attr('value')) || 0; //Selected option value
var sop; //Selected Option Price
for (i = 0; i <= data.length; i++) {
if (data[i].partid == sov) {
sop = data[i].price;
total += sop;
$('#totalprice').html(total);
break;
}
};
//debugger;
$(this).find('option').each(function () {
// $(this).append('<span></span>');
var uov = parseInt($(this).attr('value')) || 0; //Unselected option value
var uop; //Unselected Option Price
for (d = 0; d <= data.length; d++) {
if (data[d].partid == uov) {
uop = data[d].price;
break;
}
}
//debugger;
var newtext = uop - sop;
//{ newtext = "" };
//if (newtext = 0) { newtext.toString; newtext = ""; };
//debugger;
var xtext = $(this).text().toString();
//if (xtext.match(/\[.*\]/) != null) {
xtext.replace(/\s*\[[\s\S]*?\]\s*/g, '').trim();
//}
// var temp = xtext.split('[')[0];
// var temp2 = xtext.split(']')[1];
// resultx = temp + temp2;
if (newtext != 0) {
//xtext.replace(/[.*?]/, "");
$(this).attr("text", xtext + " " + "[" + "$" + newtext + "]");
};
});
});
};
You can also use a regular expression, as Jon Martin pointed out:
var yum = "donut[$25]";
yum.replace(/[.*?]/, ""); // returns "donut"
Alternatively:
var temp = foo.split('[')[0];
var temp2 = foo.split(']')[1];
foo = temp + temp2;
You can use regular expressions (the RegExp() object) to match strings.
var foo = "donut[$25]";
foo.match(/\[.*\]/);
The above will return an array of every item in [square brackets], in this case ["[$25]"].
To just get one result as a string, specify the first index like so:
foo.match(/\[.*\]/)[0];
The above will return "[$25]"
Edit: You know what? I completely misread which bit of the string you're after. This is what you're after:
var foo = "donut[$25]";
foo.match(/\w*/)[0];
How about simply;
var yum = "donut[$25]";
print( yum.substr(0, yum.indexOf("[")) );
>>donut
var begin = foo.search("[");
var end = foo.search("]");
var result = foo.substr(0, begin) + foo.substr(end+1); //Combine anything before [ and after ]
Should be ok right?
Your question leaves unspecified the treatment of the spaces before the [ character, anything after the ], will your string ever contain a linefeed character, multiple occurrences of [..], leading or trailing spaces.
The following will replace all occurrences of 'spaces [ ... ] spaces' with a single space, then it trims the result to remove any leading/trailing spaces.
v.replace (/\s*\[[\s\S]*?\]\s*/g, ' ').trim ();

What's the best way to count keywords in JavaScript?

What's the best and most efficient way to count keywords in JavaScript? Basically, I'd like to take a string and get the top N words or phrases that occur in the string, mainly for the use of suggesting tags. I'm looking more for conceptual hints or links to real-life examples than actual code, but I certainly wouldn't mind if you'd like to share code as well. If there are particular functions that would help, I'd also appreciate that.
Right now I think I'm at using the split() function to separate the string by spaces and then cleaning punctuation out with a regular expression. I'd also want it to be case-insensitive.
Cut, paste + execute demo:
var text = "Text to be examined to determine which n words are used the most";
// Find 'em!
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
// Sort 'em!
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
// Come back any time, straaanger!
var n = 10;
var message = ["The top " + n + " words are:"];
for (var i = 0; i < n; i++)
{
message.push(wordList[i][0] + " - " + wordList[i][1] + " occurance" +
(wordList[i][1] == 1 ? "" : "s"));
}
alert(message.join("\n"));
Reusable function:
function getTopNWords(text, n)
{
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
var topWords = [];
for (var i = 0; i < n; i++)
{
topWords.push(wordList[i][0]);
}
return topWords;
}
Once you have that array of words cleaned up, and let's say you call it wordArray:
var keywordRegistry = {};
for(var i = 0; i < wordArray.length; i++) {
if(keywordRegistry.hasOwnProperty(wordArray[i]) == false) {
keywordRegistry[wordArray[i]] = 0;
}
keywordRegistry[wordArray[i]] = keywordRegistry[wordArray[i]] + 1;
}
// now keywordRegistry will have, as properties, all of the
// words in your word array with their respective counts
// this will alert (choose something better than alert) all words and their counts
for(var keyword in keywordRegistry) {
alert("The keyword '" + keyword + "' occurred " + keywordRegistry[keyword] + " times");
}
That should give you the basics of doing this part of the work.
Try to split you string on words and count the resulting words, then sort on the counts.
This builds upon a previous answer by insin by only having one loop:
function top_words(text, n) {
// Split text on non word characters
var words = text.toLowerCase().split(/\W+/)
var positions = new Array()
var word_counts = new Array()
for (var i=0; i<words.length; i++) {
var word = words[i]
if (!word) {
continue
}
if (typeof positions[word] == 'undefined') {
positions[word] = word_counts.length
word_counts.push([word, 1])
} else {
word_counts[positions[word]][1]++
}
}
// Put most frequent words at the beginning.
word_counts.sort(function (a, b) {return b[1] - a[1]})
// Return the first n items
return word_counts.slice(0, n)
}
// Let's see if it works.
var text = "Words in here are repeated. Are repeated, repeated!"
alert(top_words(text, 3))
The result of the example is: [['repeated',3], ['are',2], ['words', 1]]
I would do exactly what you have mentioned above to isolate each word. I would then probably add each word as the index of an array with the number of occurrences as the value.
For example:
var a = new Array;
a[word] = a[word]?a[word]+1:1;
Now you know how many unique words there are (a.length) and how many occurrences of each word existed (a[word]).

Categories

Resources