RegExp to match words wrapped in braces - javascript

In javascript, I've got a block of HTML like this:
<h2>{title}</h2>
<p>{content}</p>
And I'm trying use regex "match" to spit out an array of all the {item}'s. So my output should look like:
['title', 'url', 'content']
I've gotten as far as:
var pattern = new RegExp("\{[a-zA-Z]+\}+");
var match = pattern.exec("{Sample} bob {text}");
But it's only returning the first tag.
This is just beyond my regex skills. Can anyone help?
Cheers!

You need to create a pattern with the global flag:
var pattern = new RegExp("\{[a-zA-Z]+\}", "g");
or:
var pattern = /\{[a-zA-Z]+\}/g;
Then you can call the match() method on your string to get a list of matches:
var matches = "{Sample} bob {text}".match(pattern);

I think you want:
var pattern = new RegExp("\{[a-zA-Z]+\}+", "g");
The second option is a flag telling it to search the entire string and return all matches.
See: http://www.evolt.org/article/Regular_Expressions_in_JavaScript/17/36435/ for more details.

Have you tried this yet?
<script>
var text = '<h2>{title}</h2>\n<p>{content}</p>';
var regex = /\{[a-z]+\}/ig;
var result = text.match(regex);
for (var i = 0; i < result.length; i++) {
console.debug(i + ". " + result[i]);
}
/*
gives:
0. {title}
1. {test}
2. {url}
3. {content}
*/
</script>

Much as I like to roll my own RegExp (and you really just need the global flag), have you looked at prototype templates, Trimpath JST or anything like that?
Because possibly rolling your own won't be as efficient for reuse as the above examples. EG:
String.prototype.template = function (obj) {
return this.replace(/{([^{}]+)}/g,
function (full, word) {
return((typeof obj[word]==='string'||typeof obj[word]==='number')?obj[word]:full);
}
);
};
"The {adj1} {adj2} {noun}.".template({adj1: 'lazy',adj2: 'brown', noun: 'dog'})
==> "The lazy brown dog."
This runs your regex each time, while I believe the prototype templates basically does it once.

I got off path by using exec for testing.

Related

what is best way to match words from list to words from sentence in javascript?

i have two sentences and i would like to find all the words they share regardless of capitalization or punctuation.
currently this is what I am doing:
searchWords = sentence1.split(" ");
var wordList = sentence2.split(" ");
const matchList = wordList.filter(value => -1 !== searchWords.indexOf(value));
it works ok but obviously capitalization and punctuation cause issues.
i know i need to incorporate something like .match() in there but i don't know how to work with it. I am sure this is something someone has done before just havent found the code yet, any refrences are also appreciated.
Thank you,
Best
This dude.
If you're looking for any words that match you can use RegExp with String.prototype.replace and verify a match using String.prototype.search with a created RegExp and an i flag to allow case insensitivity.
function compare(str1, str2, matches = []) {
str1.replace(/(\w+)/g, m => str2.search(new RegExp(m, "i")) >= 0 && matches.push(m));
return matches;
}
console.log( compare("Hello there this is a test", "Hello Test this is a world") );
If you're looking for specific words that match you can use functional composition to split each string into an Array, filter each by possible matches, and then filter one against the other.
function compare(str1, str2, matchables) {
let containFilter = (a) => (i) => a.includes(i),
matchFilter = s => s.toLowerCase().split(" ").filter(containFilter(matchables));
return matchFilter(str1).filter(containFilter( matchFilter(str2) ));
}
let matchables = ["hello", "test", "world"];
console.log( compare("Hello there this is a test", "Hi Test this is a world", matchables) );
I think you may be over-thinking this. Would just converting both sentences to an array and using a for loop to cycle through the words work? For example:
var searchWords = sentence1.split(" ");
var wordList = sentence2.toLowerCase().split(" ");
var commonWords = [];
for(var i = 0; i < searchWords.length; i++){
if(wordList.includes(searchWords[i].toLowerCase())){
commonWords.push(searchWords[i])
}
}
console.log(commonWords);
Or some variation of that.
As for the punctuation, you could probably add .replace(/[^A-Za-z0-9\s]/g,"") to the end of searchWords[i].toLowerCase() as mentioned in the following answer: https://stackoverflow.com/a/33408855/10601203

Regex: .exec() function not returning expected output

This doesn't return what I, or regex101, expects:
var myString = "Accel World|http://www.anime-planet.com/anime/accel-worldAh! My Goddess|http://www.anime-planet.com/anime/ah-my-goddess";
var reg = /[^|]*/g;
var regResponse = reg.exec(myString);
console.log(regResponse);
according to regex101, this should match everything except '|' and return it yet it only matches the first string, Accel World, as opposed to everything but '|'.
How do I fix this?
Exec will only return one result at a time (subsequent calls will return the rest, but you also need to use the + instead of *)
You could use the myString.match(reg) htough to get all results in one go.
var myString = "Accel World|http://www.anime-planet.com/anime/accel-worldAh! My Goddess|http://www.anime-planet.com/anime/ah-my-goddess";
var reg = /[^|]+/g;
var regResponse = myString.match(reg);
console.log(regResponse);
You need to loop .exec() to retrieve all matches. The documentation says
If your regular expression uses the "g" flag, you can use the exec()
method multiple times to find successive matches in the same string.
var reg = /[^|]+/g;
while(regResponse = reg.exec(myString)) {
console.log(regResponse);
}
Try a "+" instead of the "*"
So,
var reg = /[^|]+/g;

Reg Expression - In javascript how can I get the 2nd instance?

I have a string like:
some people may work for some thing new.
I need to fetch the 2nd instance of the word 'some' using javascript reg exp.
how can i get that?
here is my try:
var text = "some people may work for some thing new";
var patt = /some/.test(text);
console.log(patt);
But I am getting simply 'true' in console. But I need to get the word to be consoled. ( even i may need to replace too).
any one help me?
You need to use .match with the regex, and also use the g flag for global
var text = "some people may work for some thing new";
var patt = /some/g;
var matches = text.match(patt);
console.log( matches );
console.log( matches[1] );
Will give you an array of all instances of the word some
var text = "some people may work for some thing new";
var patt = text.match(/some/g);
console.log(patt);
will give you all the instances of the word you want to find in the sentence.
Then you can simply use replace similarly.
Suppose you want to search and replace the second word some.
Then just see this question
In addition to that you can also do something like this:
function doit(str, tobereplaced, occurence, withwhat){
var res = str.split(tobereplaced);
console.log(res);
var foo = []
for (var i = 0; i < occurence; i++) {
foo.push(res[i]);
}
var bar = []
for (var j = occurence; j < res.length; j++) {
bar.push(res[i]);
}
return foo.join("")+withwhat+bar.join("");
}
var str = "ssfds some people may work for some thing new some thing again some again";
doit(str, "some", 2, "bomb");
You can use the match method of the string to get an array of all the occurrences:
text.match(/some/g)
You need the 'g' flag in the regex otherwise the match will stop after the first hit
Here is how you replace the 2nd instance:
'some people may work for some thing new.'.replace(/(\bsome\b.*?)\bsome\b/, "$1foo");
//=> some people may work for foo thing new.
use the function exec(text) instend of test(text)
replace your code:
var patt = /some/.test(text);
to:
var patt = /some/.exec(text);

regex to find a string that comes after =

I´m really new to regex and I have been looking around to find an answer but either it dont work or I get some kind of error so I will try to ask the question and hopefulyl somebody can guide me through it :)
I have a string that can look like this:
str = "car[brand=saab][wheels=4]"
I have no idea if you can get several different matches directly or if you need different .match() but anyhow.
I need everything before the first [] in 1 variable.
Then i need saab in another, and 4 in a third.
.replace with a callback function is your tool of choice when parsing custom formats in javascript. Consider:
parse = function(s) {
var result = {};
s.replace(/^(\w+)|\[(.+?)=(.+?)\]/g, function($0, $1, $2, $3) {
result[$2 || "kind"] = $1 || $3;
});
return result;
}
Example:
str = "car[brand=saab][wheels=4][price=1234][morestuff=foobar]"
console.log(parse(str))
// {"kind":"car","brand":"saab","wheels":"4","price":"1234","morestuff":"foobar"}
You can use this regex:
([^\[]*)\[[^=]+=([^\]]*)\]\[[^=]+=([^\]]*)\]
You can then grap matching group #1, #2 and #3
Live Demo: http://www.rubular.com/r/XNZfHcMAp8
In Javascript:
str = 'car[brand=saab][wheels=4]';
console.log('match::' + str.match(/([^[]*)\[[^=]+=([^\]]*)\]\[[^=]+=([^\]]*)\]/));
I think this should work :
([^[]+)(?:\[[^=]+=([^\]]+)\])+
Explainations :
([^[]) First, you match everything that is not a [.
(?:...)+ Then, when you find it, you're starting repeting a pattern
\[[^=] Find everything that is not an =, and discard it.
([^\]]) Find everything that is not a ] and capture it.
/([^\[]+)\[brand=([^\]]+)\]\[wheels=(\d)\]/
Works.
Try it like
var result = "car[brand=saab][wheels=4]".match(/([^\[]+)\[brand=([^\]]+)\]\[wheels=(\d)\]/)
Result would be
[ "car[brand=saab][wheels=4]", "car", "saab", "4" ]
you could do it with match in one shot, and get an array back.
below lines were tested in chrome console:
str = "car[brand=saab][wheels=4]";
"car[brand=saab][wheels=4]"
str.match(/[^=[\]]+(?=[[\]])/g)
["car", "saab", "4"]
function getObject(str) {
var props = str.split(/\[(.*?)\]/g),
object = {};
if (props.length) {
object.name = props.shift();
while (props.length) {
var prop = props.shift().split("=");
if(prop.length == 2){
object[prop[0]] = prop[1];
}
}
}
return object;
}
console.log(getObject("car[brand=saab][wheels=4]"));

Javascript: highlight substring keeping original case but searching in case insensitive mode

I'm trying to write a "suggestion search box" and I cannot find a solution that allows to highlight a substring with javascript keeping the original case.
For example if I search for "ca" I search server side in a case insensitive mode and I have the following results:
Calculator
calendar
ESCAPE
I would like to view the search string in all the previous words, so the result should be:
Calculator
calendar
ESCAPE
I tried with the following code:
var reg = new RegExp(querystr, 'gi');
var final_str = 'foo ' + result.replace(reg, '<b>'+querystr+'</b>');
$('#'+id).html(final_str);
But obviously in this way I loose the original case!
Is there a way to solve this problem?
Use a function for the second argument for .replace() that returns the actual matched string with the concatenated tags.
Try it out: http://jsfiddle.net/4sGLL/
reg = new RegExp(querystr, 'gi');
// The str parameter references the matched string
// --------------------------------------v
final_str = 'foo ' + result.replace(reg, function(str) {return '<b>'+str+'</b>'});
$('#' + id).html(final_str);​
JSFiddle Example with Input: https://jsfiddle.net/pawmbude/
ES6 version
const highlight = (needle, haystack) =>
haystack.replace(
new RegExp(needle, 'gi'),
(str) => `<strong>${str}</strong>`
);
nice results with
function str_highlight_text(string, str_to_highlight){
var reg = new RegExp(str_to_highlight, 'gi');
return string.replace(reg, function(str) {return '<span style="background-color:#ffbf00;color:#fff;"><b>'+str+'</b></span>'});
}
and easier to remember...
thx to user113716: https://stackoverflow.com/a/3294644/2065594
While the other answers so far seem simple, they can't be really used in many real world cases as they don't handle proper text HTML escaping and RegExp escaping. If you want to highlight every possible snippet, while escaping the text properly, a function like that would return all elements you should add to your suggestions box:
function highlightLabel(label, term) {
if (!term) return [ document.createTextNode(label) ]
const regex = new RegExp(term.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'), 'gi')
const result = []
let left, match, right = label
while (match = right.match(regex)) {
const m = match[0], hl = document.createElement('b'), i = match.index
hl.innerText = m
left = right.slice(0, i)
right = right.slice(i + m.length)
result.push(document.createTextNode(left), hl)
if (!right.length) return result
}
result.push(document.createTextNode(right))
return result
}
string.replace fails in the general case. If you use .innerHTML, replace can replace matches in tags (like a tags). If you use .innerText or .textContent, it will remove any tags there were previously in the html. More than that, in both cases it damages your html if you want to remove the highlighting.
The true answer is mark.js (https://markjs.io/). I just found this - it is what I have been searching for for such a long time. It does just what you want it to.
I do the exact same thing.
You need to make a copy.
I store in the db a copy of the real string, in all lower case.
Then I search using a lower case version of the query string or do a case insensitive regexp.
Then use the resulting found start index in the main string, plus the length of the query string, to highlight the query string within the result.
You can not use the query string in the result since its case is not determinate. You need to highlight a portion of the original string.
.match() performs case insensitive matching and returns an array of the matches with case intact.
var matches = str.match(queryString),
startHere = 0,
nextMatch,
resultStr ='',
qLength = queryString.length;
for (var match in matches) {
nextMatch = str.substr(startHere).indexOf(match);
resultStr = resultStr + str.substr(startHere, nextMatch) + '<b>' + match + '</b>';
startHere = nextMatch + qLength;
}
I have found a easiest way to achieve it. JavaScript regular expression remembers the string it matched. This feature can be used here.
I have modified the code a bit.
reg = new RegExp("("+querystr.trim()+")", 'gi');
final_str = 'foo ' + result.replace(reg, "<b>&1</b>");
$('#'+id).html(final_str);
Highlight search term and anchoring to first occurence - Start
function highlightSearchText(searchText) {
var innerHTML = document.documentElement.innerHTML;
var replaceString = '<mark>'+searchText+'</mark>';
var newInnerHtml = this.replaceAll(innerHTML, searchText, replaceString);
document.documentElement.innerHTML = newInnerHtml;
var elmnt = document.documentElement.getElementsByTagName('mark')[0]
elmnt.scrollIntoView();
}
function replaceAll(str, querystr, replace) {
var reg = new RegExp(querystr, 'gi');
var final_str = str.replace(reg, function(str) {return '<mark>'+str+'</mark>'});
return final_str
}
Highlight search term and anchoring to first occurence - End

Categories

Resources