I'm trying to replace part of a string with the same number of dummy characters in JavaScript, for example: '==Hello==' with '==~~~~~=='.
This question has been answered using Perl and PHP, but I can't get it to work in JavaScript. I've been trying this:
txt=txt.replace(/(==)([^=]+)(==)/g, "$1"+Array("$2".length + 1).join('~')+"$3");
The pattern match works fine, but the replacement does not - the second part adds '~~' instead of the length of the pattern match. Putting the "$2" inside the parentheses doesn't work. What can I do to make it insert the right number of characters?
Use a function for replacement instead:
var txt = "==Hello==";
txt = txt.replace(/(==)([^=]+)(==)/g, function ($0, $1, $2, $3) {
return $1 + (new Array($2.length + 1).join("~")) + $3;
});
alert(txt);
//-> "==~~~~~=="
The issue with the expression
txt.replace(/(==)([^=]+)(==)/g, "$1"+Array("$2".length + 1).join('~')+"$3")
is that "$2".length forces $2 to be taken as a string literal, namely the string "$2", that has length 2.
From the MDN docs:
Because we want to further transform the result of the match before the final substitution is made, we must use a function.
This forces evaluation of the match before the transformation.
With an inline function as parameter (and repeat) -- here $1, $2, $3 are local variables:
txt.replace(/(==)([^=]+)(==)/g, (_,$1,$2,$3) => $1+'~'.repeat($2.length)+$3);
txt = '==Hello==';
//inline function
console.log(
txt.replace(/(==)([^=]+)(==)/g, (_, g1, g2, g3) => g1 + '~'.repeat(g2.length) + g3)
);
The length attribute is being evaluated before the $2 substitution so replace() won't work. The function call suggested by Augustus should work, another approach would be using match() instead of replace().
Using match() without the /g, returns an array of match results which can be joined as you expect.
txt="==Hello==";
mat=txt.match(/(==)([^=]+)(==)/); // mat is now ["==Hello==","==","Hello","=="]
txt=mat[1]+Array(mat[2].length+1).join("~")+mat[3]; // txt is now "==~~~~~=="
You excluded the leading/trailing character from the middle expression, but if you want more flexibility you could use this and handle anything bracketed by the leading/trailing literals.
mat=txt.match(/(^==)(.+)(==$)/)
A working sample uses the following fragment:
var processed = original.replace(/(==)([^=]+)(==)/g, function(all, before, gone, after){
return before+Array(gone.length+1).join('~')+after;
});
The problem in your code was that you always measured the length of "$2" (always a string with two characters). By having the function you can measure the length of the matched part. See the documentation on replace for further examples.
Related
I have a string like aman/gupta and I want to replace it to aman$$gupta and for that I am using JavaScript replace method as follows:
let a = "aman/gupta"
a = a.replace("/", "$")
console.log(a) // 'aman$gupta'
a = "aman/gupta"
a = a.replace("/", "$$")
console.log(a) // 'aman$gupta'
a = "aman/gupta"
a = a.replace("/", "$$$")
console.log(a) // 'aman$$gupta'
Why are the 1st and 2nd case identical and I get the expected result when I use $$$ instead of $$?
It’s because $$ inserts a literal "$".
So, you need to use:
a = "aman/gupta";
a = a.replace("/", "$$$$"); // "aman$$gupta"
See the following special patterns:
Pattern
Inserts
$$
Inserts a "$".
$&
Inserts the matched substring.
$`
Inserts the portion of the string that precedes the matched substring.
$'
Inserts the portion of the string that follows the matched substring.
$n
Where n is a non-negative integer less than 100, inserts the _n_th parenthesized submatch string, provided the first argument was a RegExp object.
$<Name>
Where Name is a capturing group name. If the group is not in the match, or not in the regular expression, or if a string was passed as the first argument to replace instead of a regular expression, this resolves to a literal (e.g., "$<Name>").
Also you can use split and join for better performance and $ isn't special for those functions.
var a = "aman/gupta"
a = a.split('/').join('$$')
alert(a); // "aman$$gupta"
To avoid the need to escape special characters you can use anonymous function as a replacer
a = "aman/gupta";
a = a.replace("/", function() {return "$$"});
console.log(a); // "aman$$gupta"
String.prototype.replace() documentation
Specifying a function as a parameter
You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function's result (return value) will be used as the replacement string. (Note: the above-mentioned special replacement patterns do not apply in this case.) Note that the function will be invoked multiple times for each full match to be replaced if the regular expression in the first parameter is global.
The replace method provides replacement patterns that start with a dollar sign. One of them is $$ which inserts a single $. A single dollar sign in the replacement string will result in a literal one.
So if you want clean literal dollar signs, use $$ replacement patterns accordingly:
console.log('aman/gupta'.replace('/','$$')); // aman$gupta
console.log('aman/gupta'.replace('/','$$$$')); // aman$$gupta
console.log('aman/gupta'.replace('/','$$$$$$')); // aman$$$gupta
In regular expression replace with groups, if replacement is a variable, it needs to dollar sign escaped. Otherwise there will be bugs.
function escapeDollarSign(str) {
return str.replace(/\$/g, "$$$$")
}
Use below code its working for me.
var dollar = "$$$$";
console.log('abhishe/kadam'.replace('/', dollar.replace(new RegExp('\\$', 'g'), '$$$')));
Am trying to find a regex expression for this result:
string => should be matched (a single word or set of words at the beginning or the ending)
string => should be matched (a single word or set of words in the middle)
{{string}} -- should not be matched (a single word or set of words surrounded by two "{}" should not be matched)
am using this regex in this function :
text = text.replace(RegExp("([^{]{2})[^(\d:)]" + aTags[index].textContent + "\w*
([^}]{2})", 'i'), "{{" + index + ":" + aTags[index].textContent + "}}");
the function should find the textContent of an 'a' tag in a 'text' string and replace it by adding a digit and ':' to the beginning of the textContent so that the result should be something like this :
some text => will became => {{1:some text}}
We can apply the good old *SKIP what's to avoid approach and throw everything that does not need to be replaced in the full match and capture the desired output in group 1:
{{[^}]+}}|(string)
To make this work effectively in JavaScript we have to use a .replace callback function:
const regex = /{{[^}]+}}|(string)/gm;
const str = `string
string
{{string}}`;
var index = 1; //this is your index var and is somehow set from outside
const result = str.replace(regex, function(m, group1) {
if (group1) return `{{${index}:${group1}}}`;
else return m;
});
console.log('Substitution result: ', result);
I had pseudo-coded this a bit since I cannot know where index and aTags[index].textContent is coming from. Adjust as needed.
You cannot use PCRE verbs like (*SKIP)(*F) in a JavaScript regex, i.e. you cannot skip a matched portion of text with the regex means only. In JavaScript, you may match and capture a part of the string you want to later analyze in the replacement callback method (JS String#replace accepts a callback as the replacement argument).
So, in your case the solution will look like
text = text.replace(RegExp("{{.*?}}|(" + aTags[index].textContent + ")", "gi"),
function ($0, $1) {
return $1 ? "{{" + index + ":" + $1 + "}}" : $0;
}
);
I understand the aTags[index].textContent value is alphanumeric, else, consider escaping it for use in a regex pattern.
The pattern will match a {{...}} substring having no } inside (with {{.*?}}) or (|) it will match and capture the text content ((aTags[index].textContent)) into Group 1. When you get a match, you need to pass 2 arguments to the callback, the whole match and Group 1 value. If Group 1 is not empty, you perform string manipulations, else, just insert the match back.
I have a string like this
var data = "{45}*[52]*{45}*[52]*{45}*[52]*69"
I need to replace all the square bracket & curly brackets to round brackets in javascript or jquery
I have tried this
.replace(/[\[\]']+/g,'')
but it replaces all the open and close brackets parallel
Expected result is = "(45)*(52)*(45)*(52)*(45)*(52)*69"
Any ideas ?
In a simple way you can use
"{45}*[52]*{45}*[52]*{45}*[52]*69".split(/[\{\[]/).join('(').split(/[\}\]]/).join(')')
You can call .replace() with a function as the second parameter.
With this function you can create a new substring which will be used as replacement.
str.replace(regexp|substr, newSubStr|function[, flags])
function (replacement)
A function to be invoked to create the new
substring (to put in place of the substring received from parameter
1). The arguments supplied to this function are described in the "Specifying a function as a parameter" section below.
Specifying a function as a parameter
You can specify a function as the second parameter. In this case, the
function will be invoked after the match has been performed. The
function's result (return value) will be used as the replacement
string. (Note: the above-mentioned special replacement patterns do not
apply in this case.) Note that the function will be invoked multiple
times for each full match to be replaced if the regular expression in
the first parameter is global.
"[abc]".replace(/\[|\]/g, function(m) {
var replacements = {"[": "(", "]": ")"}; return replacements[m];
});
in one replace
var data = "{45}*[52]*{45}*[52]*{45}*[52]*69";
data = data.replace(/[\[\{](\d+)[\]\}]/g, "($1)")
Though it will also replace [123} and {123] with (123) ... so not technically correct
if you want to only replace "correctly" formatted input, you need two replace calls
data = data.replace(/[\{](\d+)[\}]/g, "($1)").replace(/[\[](\d+)[\]]/g, "($1)")
I think
Try utilizing RegExp /(.\d{2}.)/ to match any character before two digits , two digits, any character ; .match() to match digits , return replacement string
var data = "{45}*[52]*{45}*[52]*{45}*[52]*69";
var res = data.replace(/(.\d{2}.)/g, function(match) {
return "(" + match.match(/\d+/)[0] + ")"
});
document.body.textContent = res;
I am currently using the following JavaScript code:
concatedSubstring.replace(/\//g, '-').replace(/[A-Za-z]/g, function(c){
return c.toUpperCase().charCodeAt(0)-64;
});
...to take input in the format "1234/A", "22/B", etc. and output "1234-1" , "22-2", etc.
That is, / becomes -, and the letters become integers with A = 1, B = 2, etc.
I would like to change this so that if the input doesn't contain a "/" the output will still insert a "-" in the spot where the "/" should've been. That is, the input "1234A" should output "1234-1", or "22B" should output "22-2", etc.
The following should work even for inputs containing more than one of your number/letter pattern:
var input = "1234/B 123a 535d";
var replaced = input.replace(/(\d+)(\/?)([A-Za-z])/g, function(m,p1,p2,p3) {
return p1 + "-" + (p3.toUpperCase().charCodeAt(0)-64);
});
alert(replaced); // "1234-2 123-1 535-4"
The regex:
/(\d+)(\/?)([A-Za-z])/g
...will match one or more digits followed by an optional forward slash followed by a single letter, capturing each of those parts for later use.
If you pass a callback to .replace() then it will be called with arguments for the full match (which I'm ignoring for your requirement) and also for any sub-matches (which I use).
str = "1234/B"; or str = "1234B";
str.replace(/(\/[A-Z])|([A-Z])/g,"-"+parseInt(str.charCodeAt(str.indexOf(str.match(/[A-Z]/g)))-64))
You can also .replace(/([0-9])([a-zA-Z])/g,"$1-$2"): this turns a number adjacent to a letter into numberDASHletter, using backreferences (the $1 refers to whatever was in the first set of brackets, $2 to whatever was in the second set of brackets).
RegExp can replace matched patterns with replacements involving what is known as Tagged Expressions
Example:
var s = "... some string with full things...";
s = s.replace(/(some|full)/gi, "\"aw$1\");
which will result in
'... "awsome" string with "awfull" things...'
And life are cool, because some and full are matched, and $1 in the replaced string reflects the matched Tagged Expression in the braces, in this case - exactly only some or full.
Now, that we got the idea -
I'm looking for an idea to do the following:
String before:
"{timeOfEffect: 3*24*60*60 }"
String after
"{timeOfEffect: 259200}"
The values are represented like that because they are edited by humans to graspable terms like (60 sec * 60 min * 24 hours)*3 => 3 days (don't ask. Client's request), but read in computer terms like 259200 in seconds, and could contain many occuring of that pattern.
I was thinking to try to create a replacement expression that multiplies $1 and $2, or even pass $1 and $2 to a function, or pass $1 * $2 to an evaluation context, but I have to create a function for it and do it manually.
The closest I got is
var x = /([0-9]*)\s\*\s([0-9]*)/g
, r = function(m){
return m[1] * m[2];
}
while (m = x.exec(s))
s = s.replace( x, r(m));
That sucks a little because exec returns only the first match.
After handling it in the replace statement - next search starts again from the start of the string - which is a string of 60K length...
A good solution will be one of the following:
a) perform the match starting from an index (without creating a new substring for that)
b) provide a replace expression that allows evaluation
The alternative approach will be to tokenize the string, and process it in bits - which is a total alternative to the RegExp that will take a lot of code and effort, in which case I'll just live with the performance penalty or give a better fight on a better alternative for this requirement...
Help anybody?
var s = "timeOfEffect: 3*24*60*60 var: 6*8 ";
var r = new RegExp("([0-9*+-/]{0,}[0-9])","g");
s = s.replace(r,function(match){ return eval(match); });
alert(s)
var str = '{timeOfEffect: 3*24*60*60}, {timeOfEffect: 1+7}, {timeOfEffect: 20-3}, {timeOfEffect: 3 / 0}';
var result = str.replace(/\s([\d\/\*\-\+\s]+?)\}/g, function(all, match) {
return eval(match) + '}';
});
document.body.innerHTML = result;
// {timeOfEffect:259200}, {timeOfEffect:8}, {timeOfEffect:17}, {timeOfEffect:Infinity}
jsFiddle.
eval() is safe to use because we have ensured the string only contains 0-9, , \n, \t, /, *, - and +. I was hoping there may be something like Math.parse(), but there isn't.
If you need more complex math that requires parenthesis, simply add escaped ( and ) to the regex character range.