Replace Regex Multiple Matches between two strings - javascript

I'm trying to turn some text into html, but I'm having trouble building a table. Each cell is surrounded by brackets [].
I've already got the rows set:
<tr>[blue][red][yellow][purple][white]</tr>
Now I need to replace turn each cell into a <td>.
This would work fine:
.replace(/\[(.*?)\]/g,'<td>$1</td>')
but I don't want to happen in other parts of the document, just when it's in between tags.
This makes sense to me, but just doesn't work:
.replace(/(<tr>.*?)\[(.*?)\](.*?\<\/tr\>)/g,'$1<td>$2</td>$3')
here is a full code if you want to try it:
alert('<tr>[blue][red][yellow][purple][white]</tr>'.replace(/(<tr>.*?)\[(.*?)\](.*?\<\/tr\>)/g,'$1<td>$2</td>$3'));
it outputs:
<tr><td>blue</td>[red][yellow][purple][white]</tr>
expected output:
<tr><td>blue</td><td>red</td><td>yellow</td><td>purple</td><td>white</td></tr>

You can do this easily in two steps:
var str = "<div>[do not replace]</div><table><tr>[blue][red][yellow][purple][white]</tr></table>";
str = str.replace(/(<tr[\s\S]*?>)([\s\S]*?)(<\/tr>)/g, function(m, start, contents, end) {
return start + contents.replace(/\[([\s\S]*?)\]/g, "<td>$1</td>") + end;
});
alert(str);
Note that I replaced what should have been . with [\s\S] to simulate the s regex option that JS unfortunately lacks.

A way that use a split/join in the replacement function:
var str = '<tr>[blue][red][yellow][purple][white]</tr>';
var res = str.replace(/<tr>(?:\[[^\]]*\])+<\/tr>/g,
function (m) {
return '<tr><td>'
+ m.substring(5, m.length-6).split('][').join('</td><td>')
+ '</td><tr>';
});
console.log(res);

Related

Problems with first blank value while building a delimiter parser using regex

I'm building this generic parser that decodes a string to an Array using an specified delimiter.
For this question, I'll use comma as delimiter.
This is my current regex:
var reg = /(\,|\r?\n|\r|^)(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|([^"\,\r\n]*))/gi
It works fine for most cases like:
'a,b,c,d'.match(reg);
returns
["a", ",b", ",c", ",d"] (having the commas with the values is not a problem)
When I have empty values, it also works, for example:
'a,,c,'.match(reg);
returns ["a", ",", ",c", ","] (this is also fine)
The problem is when I have a blank value at the first position:
',b,c,d'.match(reg);
returns [",b", ",c", ",d"] and I was expecting something like: ["", ",b", ",c", ",d"]
Any ideas?
If you want to split by , then the regex is very simple: /,/g.
You can then pass this pattern into the split function.
It will also work with multi-character delimiters e.g. foo.
You can then do something like this:
var pattern = /,/g;
var el = document.getElementById('out');
el.insertAdjacentHTML('beforeend', '<p>Trying with ,</p>');
output('a,b,c,d');
output(',b,c,d');
output(',,,d');
output('a,,c,');
el.insertAdjacentHTML('beforeend', '<p>Trying with foo</p>');
var pattern = /foo/g;
output('afoobfoocfood');
output('foobfoocfood');
output('foofoofood');
output('afoofoocfoo');
function output(input) {
var item = '<p>' + input + ' gives: ';
var arr = input.split(pattern);
item += '<pre>' + JSON.stringify(arr) + '</pre></p>';
el.insertAdjacentHTML('beforeend', item);
}
<div id="out"></div>
How about something simpler like this regex:
[^\,]*\,(?!$)|[^\,]|\,
The regex above will catch anything between , including special characters. You can build on it to make it match specific type of characters.
This is a working js:
var reg = /[^\,]*\,(?!$)|[^\,]|\,/gi;
var s = ',,b,c,d'.match(reg);
document.write(s[0], '<br>' , s[1] , '<br>' , s[2] , '<br>' , s[3], '<br>' , s[4]);
Thanks to everyone who posted an answer but I ended up going with the solution provided here:
Javascript code to parse CSV data
The solution above also had the problem with an empty value at the first position but solving that with JS in the while loop was easier than fixing the RegEx.

append single quotes to characters

I have a string like
var test = "1,2,3,4";
I need to append single quotes (' ') to all characters of this string like this:
var NewString = " '1','2','3','4' ";
Please give me any suggestion.
First, I would split the string into an array, which then makes it easier to manipulate into any form you want. Then, you can glue it back together again with whatever glue you want (in this case ','). The only remaining thing to do is ensure that it starts and ends correctly (in this case with an ').
var test = "1,2,3,4";
var formatted = "'" + test.split(',').join("','") + "'"
var newString = test.replace(/(\d)/g, "'$1'");
JS Fiddle demo (please open your JavaScript/developer console to see the output).
For multiple-digits:
var newString = test.replace(/(\d+)/g, "'$1'");
JS Fiddle demo.
References:
Regular expressions (at the Mozilla Developer Network).
Even simpler
test = test.replace(/\b/g, "'");
A short and specific solution:
"1,2,3,4".replace(/(\d+)/g, "'$1'")
A more complete solution which quotes any element and also handles space around the separator:
"1,2,3,4".split(/\s*,\s*/).map(function (x) { return "'" + x + "'"; }).join(",")
Using regex:
var NewString = test.replace(/(\d+)/g, "'$1'");
A string is actually like an array, so you can do something like this:
var test = "1,2,3,4";
var testOut = "";
for(var i; i<test.length; i++){
testOut += "'" + test[i] + "'";
}
That's of course answering your question quite literally by appending to each and every character (including any commas etc.).
If you needed to keep the commas, just use test.split(',') beforehand and add it after.
(Further explanation upon request if that's not clear).

Replace leading spaces with in Javascript

I have text like the following, with embedded spaces that show indentation of some xml data:
<Style id="KMLStyler"><br>
<IconStyle><br>
<colorMode>normal</colorMode><br>
I need to use Javascript to replace each LEADING space with
so that it looks like this:
<Style id="KMLStyler"><br>
<IconStyle><br>
<colorMode>normal</colorMode><br>
I have tried a basic replace, but it is matching all spaces, not just the leading ones. I want to leave all the spaces alone except the leading ones. Any ideas?
JavaScript does not have the convenient \G (not even look-behinds), so there's no pure regex-solution for this AFAIK. How about something like this:
function foo() {
var leadingSpaces = arguments[0].length;
var str = '';
while(leadingSpaces > 0) {
str += ' ';
leadingSpaces--;
}
return str;
}
var s = " A B C";
print(s.replace(/^[ \t]+/mg, foo));
which produces:
A B C
Tested here: http://ideone.com/XzLCR
EDIT
Or do it with a anonymous inner function (is it called that?) as commented by glebm in the comments:
var s = " A B C";
print(s.replace(/^[ \t]+/gm, function(x){ return new Array(x.length + 1).join(' ') }));
See that in action here: http://ideone.com/3JU52
Use ^ to anchor your pattern at the beginning of the string, or if you'r dealing with a multiline string (ie: embedded newlines) add \n to your pattern. You will need to match the whole set of leading spaces at once, and then in the replacement check the length of what was matched to figure out how many nbsps to insert.

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

Regex: how to get contents from tag inner (use javascript)?

page contents:
aa<b>1;2'3</b>hh<b>aaa</b>..
.<b>bbb</b>
blabla..
i want to get result:
1;2'3aaabbb
match tag is <b> and </b>
how to write this regex using javascript?
thanks!
Lazyanno,
If and only if:
you have read SLaks's post (as well as the previous article he links to), and
you fully understand the numerous and wondrous ways in which extracting information from HTML using regular expressions can break, and
you are confident that none of the concerns apply in your case (e.g. you can guarantee that your input will never contain nested, mismatched etc. <b>/</b> tags or occurrences of <b> or </b> within <script>...</script> or comment <!-- .. --> tags, etc.)
you absolutely and positively want to proceed with regular expression extraction
...then use:
var str = "aa<b>1;2'3</b>hh<b>aaa</b>..\n.<b>bbb</b>\nblabla..";
var match, result = "", regex = /<b>(.*?)<\/b>/ig;
while (match = regex.exec(str)) { result += match[1]; }
alert(result);
Produces:
1;2'3aaabbb
You cannot parse HTML using regular expressions.
Instead, you should use Javascript's DOM.
For example (using jQuery):
var text = "";
$('<div>' + htmlSource + '</div>')
.find('b')
.each(function() { text += $(this).text(); });
I wrap the HTML in a <div> tag to find both nested and non-nested <b> elements.
Here is an example without a jQuery dependency:
// get all elements with a certain tag name
var b = document.getElementsByTagName("B");
// map() executes a function on each array member and
// builds a new array from the function results...
var text = b.map( function(element) {
// ...in this case we are interested in the element text
if (typeof element.textContent != "undefined")
return element.textContent; // standards compliant browsers
else
return element.innerText; // IE
});
// now that we have an array of strings, we can join it
var result = text.join('');
var regex = /(<([^>]+)>)/ig;
var bdy="aa<b>1;2'3</b>hh<b>aaa</b>..\n.<b>bbb</b>\nblabla..";
var result =bdy.replace(regex, "");
alert(result) ;
See : http://jsfiddle.net/abdennour/gJ64g/
Just use '?' character after the generating pattern for your inner text if you want to use Regular experssions.
for example:
".*" to "(.*?)"

Categories

Resources