Substring and regex - javascript

I have a SQL string:
var sql= "AND DT_FIM IS NULL AND ( CD_JOB, DT_INI_JOB ) IN (SELECT x.CD_JOB, x.DT_INI FROM PRS_JOBS_MAQUINA x WHERE x.CD_JOB = ':CD_JOB' AND TO_CHAR(x.DT_INI, 'YYYY-MM-DD') = ':DT_INI_JOB' AND x.DT_FIM IS NULL)
and i need to extract the binded values(:CD_JOB , :DT_INI_JOB), the problem is that with
var bindFields=sql.substring(sql.lastIndexOf("':") + 1 , sql.lastIndexOf("'"));
it returns only the first match and i need both.
Is it possible with Javascript? Lodash to the rescue if anybody find it useful.
https://jsfiddle.net/oq0dmyjo/1/ .
Apreciate your help . Thanks

You can use a very simple regex with a capturing group:
/':([^']+)/g
Explanation:
': - a literal sequence ':
([^']+) - Group 1 capturing 1 or more symbols other than '
g - a global modifier matching all instances.
Here are some resources to learn:
Capturing groups
How do you access the matched groups in a JavaScript regular expression?
JS code:
var re = /':([^']+)/g;
var str = "AND DT_FIM IS NULL AND ( CD_JOB, DT_INI_JOB ) IN (SELECT x.CD_JOB, x.DT_INI FROM PRS_JOBS_MAQUINA x WHERE x.CD_JOB = ':CD_JOB' AND TO_CHAR(x.DT_INI, 'YYYY-MM-DD') = ':DT_INI_JOB' AND x.DT_FIM IS NULL)";
var res = [];
while ((m = re.exec(str)) !== null) {
res.push(m[1]);
}
document.body.innerHTML = "<pre>" + JSON.stringify(res, 0, 4) + "</pre>";

Since it looks like you're binding the fields, you probably want to use replace with a replacement function. Use the regex from #WiktorStribiżew, /':([^']+)'/g, but then use it like this:
var sql = "AND DT_FIM IS NULL AND ( CD_JOB, DT_INI_JOB ) IN (SELECT x.CD_JOB, x.DT_INI FROM PRS_JOBS_MAQUINA x WHERE x.CD_JOB = ':CD_JOB' AND TO_CHAR(x.DT_INI, 'YYYY-MM-DD') = ':DT_INI_JOB' AND x.DT_FIM IS NULL)";
var fields = {
CD_JOB: 1,
DT_INI_JOB: 2
};
sql = sql.replace(/':([^']+)'/g, function($0, $1) {
return fields[$1];
});
console.log(sql);

Related

Replace all “?” by “&” except first

I’d would to replace all “?” by “&” except the first one by javascript. I found some regular expressions but they didn’t work.
I have something like:
home/?a=1
home/?a=1?b=2
home/?a=1?b=2?c=3
And I would like:
home/?a=1
home/?a=1&b=2
home/?a=1&b=2&c=3
Someone know how to I can do it?
Thanks!
I don't think it's possible with regex but you can split the string and then join it back together, manually replacing the first occurance:
var split = 'home/?a=1?b=2'.split('?'); // [ 'home/', 'a=1', 'b=2' ]
var replaced = split[0] + '?' + split.slice(1).join('&') // 'home/?a=1&b=2'
console.log(replaced);
You could match from the start of the string not a question mark using a negated character class [^?]+ followed by matching a question mark and capture that in the first capturing group. In the second capturing group capture the rest of the string.
Use replace and pass a function as the second parameter where you return the first capturing group followed by the second capturing group where all the question marks are replaced by &
let strings = [
"home/?a=1",
"home/?a=1?b=2",
"home/?a=1?b=2?c=3"
];
strings.forEach((str) => {
let result = str.replace(/(^[^?]+\?)(.*)/, function(match, group1, group2) {
return group1 + group2.replace(/\?/g, '&')
});
console.log(result);
});
You can split it by "?" and then rewrap the array:
var string = "home/?a=1?b=2";
var str = string.split('?');
var new = str[0] + '?'; // text before first '?' and first '?'
for( var x = 1; x < str.length; x++ ) {
new = new + str[x];
if( x != ( str.length - 1 ) ) new = new + '&'; //to avoid place a '&' after the string
}
You can use /([^\/])\?/ as pattern in regex that match any ? character that isn't after / character.
var str = str.replace(/([^\/])\?/g, "$1&");
var str = "home/?a=1\nhome/?a=1?b=2\nhome/?a=1?b=2?c=3\n".replace(/([^\/])\?/g, "$1&");
console.log(str);

How can I replace multiple characters in a string?

I want to create a regex with following logic:
1., If string contains T replace it with space
2., If string contains Z remove Z
I wrote two regex already, but I can't combine them:
string.replace(/\T/g,' ') && string.replace(/\Z/g,'');
EDIT: I want the regex code to be shorter
Doesn't seem this even needs regex. Just 2 chained replacements would do.
var str = '[T] and [Z] but not [T] and [Z]';
var result = str.replace('T',' ').replace('Z','');
console.log(result);
However, a simple replace only replaces the first occurence.
To replace all, regex still comes in handy. By making use of the global g flag.
Note that the characters aren't escaped with \. There's no need.
var str = '[T] and [Z] and another [T] and [Z]';
var result = str.replace(/T/g,' ').replace(/Z/g,'');
console.log(result);
// By using regex we could also ignore lower/upper-case. (the i flag)
// Also, if more than 1 letter needs replacement, a character class [] makes it simple.
var str2 = '(t) or (Ⓣ) and (z) or (Ⓩ). But also uppercase (T) or (Z)';
var result2 = str2.replace(/[tⓉ]/gi,' ').replace(/[zⓏ]/gi,'');
console.log(result2);
But if the intention is to process really big strings, and performance matters?
Then I found out in another challenge that using an unnamed callback function inside 1 regex replace can prove to be faster. When compared to using 2 regex replaces.
Probably because if it's only 1 regex then it only has to process the huge string once.
Example snippet:
console.time('creating big string');
var bigstring = 'TZ-'.repeat(2000000);
console.timeEnd('creating big string');
console.log('bigstring length: '+bigstring.length);
console.time('double replace big string');
var result1 = bigstring.replace(/[t]/gi,'X').replace(/[z]/gi,'Y');
console.timeEnd('double replace big string');
console.time('single replace big string');
var result2 = bigstring.replace(/([t])|([z])/gi, function(m, c1, c2){
if(c1) return 'X'; // if capture group 1 has something
return 'Y';
});
console.timeEnd('single replace big string');
var smallstring = 'TZ-'.repeat(5000);
console.log('smallstring length: '+smallstring.length);
console.time('double replace small string');
var result3 = smallstring.replace(/T/g,'X').replace(/Z/g,'Y');
console.timeEnd('double replace small string');
console.time('single replace small string');
var result4 = smallstring.replace(/(T)|(Z)/g, function(m, c1, c2){
if(c1) return 'X';
return 'Y';
});
console.timeEnd('single replace small string');
Do you look for something like this?
ES6
var key = {
'T': ' ',
'Z': ''
}
"ATAZATA".replace(/[TZ]/g, (char) => key[char] || '');
Vanilla
"ATAZATA".replace(/[TZ]/g,function (char) {return key[char] || ''});
or
"ATAZATA".replace(/[TZ]/g,function (char) {return char==='T'?' ':''});
you can capture both and then decide what to do in the callback:
string.replace(/[TZ]/g,(m => m === 'T' ? '' : ' '));
var string = 'AZorro Tab'
var res = string.replace(/[TZ]/g,(m => m === 'T' ? '' : ' '));
console.log(res)
-- edit --
Using a dict substitution you can also do:
var string = 'AZorro Tab'
var dict = { T : '', Z : ' '}
var re = new RegExp(`[${ Object.keys(dict).join('') }]`,'g')
var res = string.replace(re,(m => dict[m] ) )
console.log(res)
Second Update
I have developed the following function to use in production, perhaps it can help someone else. It's basically a loop of the native's replaceAll Javascript function, it does not make use of regex:
function replaceMultiple(text, characters){
for (const [i, each] of characters.entries()) {
const previousChar = Object.keys(each);
const newChar = Object.values(each);
text = text.replaceAll(previousChar, newChar);
}
return text
}
Usage is very simple:
const text = '#Please send_an_information_pack_to_the_following_address:';
const characters = [
{
"#":""
},
{
"_":" "
},
]
const result = replaceMultiple(text, characters);
console.log(result); //'Please send an information pack to the following address:'
Update
You can now use replaceAll natively.
Outdated Answer
Here is another version using String Prototype. Enjoy!
String.prototype.replaceAll = function(obj) {
let finalString = '';
let word = this;
for (let each of word){
for (const o in obj){
const value = obj[o];
if (each == o){
each = value;
}
}
finalString += each;
}
return finalString;
};
'abc'.replaceAll({'a':'x', 'b':'y'}); //"xyc"

Javascript Regex to replace "=" to "==" without having any special character having it

I need to replace the = to == using the JavaScript on the condition it should not replace if is already as
==
>=
<=
=>
=<
Can anyone help me in this with the explanation. I am trying like below but it was replacing all.
text = text.replace(/=/, "==");
Input :
Premium UserId=5||Premium UserId>=2
Output Needed:
Premium UserId==5||Premium UserId>=2
Use the following regex:
var str = 'Premium UserId=5||Premium = UserId>=2',
re = /([^=><])=([^=><]*?)/g;
console.log(str.replace(re, "$1==$2"));
You should use this opportunity to learn about regular expression lookaround. Unfortunately, while JavaScript supports lookahead, it doesn't support lookbehind. Therefore, while the regex /=(?![>=<])/ will successfully avoid the following matches: =< and =>, it'll still match everything else.
However, there are ways to simulate lookbehind in Javascript. You can use the following code snippet to achieve what you're trying to do:
var text = 'Premium UserId=5||Premium UserId>=2';
text = text.replace(/([>=<])?=(?![>=<])/g, function($0, $1) {
return $1 ? $0 : $0 + '=';
});
console.log(text)
maybe something like this? (will not match the very beginning or end of text...)
text=text.replace(/([^=><])=([^=><])/g, function (match,p1,p2){ return p1+"=="+p2; });
var text = "Premium UserId=5||Premium UserId>=2";
text=text.replace(/([^=><])=([^=><])/g, function (match,p1,p2){ return p1+"=="+p2; });
console.log(text)
Try this approach
var input = "Premium UserId=5||Premium UserId>=2";
var regex = new RegExp( "(?:[0-9a-z\s])=(?![<>])", "gi" );
var output = input.replace( regex , function(match){ return match.charAt(0) + "==" } );
console.log(output);
console.log("Premium UserId =5||Premium UserId>=2".replace( /(?:[0-9a-z\s])=(?![<>])/gi, function(match){ return match.charAt(0) + "==" } ));
console.log("Premium UserId =>5||Premium UserId>=2".replace( /(?:[0-9a-z\s])=(?![<>])/gi, function(match){ return match.charAt(0) + "==" } ));
var re = /(([^<>=])(={1,1})([^<>=]))/g
var tests = [
{in: 'Premium UserId=5||Premium UserId>=2', out: 'Premium UserId==5||Premium UserId>=2'},
{in: 'if (UserId == 5)', out: 'if (UserId == 5)'}
]
tests.forEach(function(test, idx){
var result = test.in.replace(re, '$2==$4') === test.out
console.log('test', idx, result)
})

A simpler way to capture multiple variables in javascript regexps

Comming from the perl/python world I was wondering if there is a simpler way to filter out multiple captured variables from regexp in javascript:
#!/usr/bin/env node
var data=[
"DATE: Feb 26,2015",
"hello this should not match"
];
for(var i=0; i<data.length; i++) {
var re = new RegExp('^DATE:\\s(.*),(.*)$');
if(data[i].match(re)) {
//match correctly, but how to get hold of the $1 and $2 ?
}
if(re.exec(data[i])) {
//match correctly, how to get hold of the $1 and $2 ?
}
var ret = '';
if(data[i].match(re) && (ret = data[i].replace(re,'$1|$2'))) {
console.log("line matched:" + data[i]);
console.log("return string:" + ret);
ret = ret.split(/\|/g);
if (typeof ret !== 'undefined') {
console.log("date:" + ret[0], "\nyear:" + ret[1]);
}
else {
console.log("match but unable to parse capturing parentheses");
}
}
}
The last condition works, but you need a temp var and split it, and you need to have a test in front because the replace works on everything.
Output is:
$ ./reg1.js
line matched:DATE: Feb 26,2015
return string:Feb 26|2015
date:Feb 26
year:2015
If I look up: mosdev regexp it says on (x):
The matched substring can be recalled from the resulting array's
elements 1, ..., [n] or from the predefined RegExp object's
properties $1, ..., $9.
How do I get hold of the RegExp objects' $1 and $2?
Thanks
The MDN is a good resource for learning Javascript. In this particular case, .match(), .exec(), etc. all return objects containing match information. That is where you'll find captured groups.
Thanks for the answer found that they return an array:, so the simpler blocks can look like this:
if((ret = data[i].match(re))!=null) {
//match correctly, but how to get hold of the $1 and $2 ?
console.log("line matched:" + data[i]);
console.log("return string:" + ret[0] + "|" + ret[1]);
ret = null;
}
if((ret = re.exec(data[i]))!=null) {
//match correctly, how to get hold of the $1 and $2 ?
console.log("line matched:" + data[i]);
console.log("return string:" + ret[0] + "|" + ret[1]);
ret = null;
}
Using JavaScript .test() and .match() this can be very simple
An example:
var input = "DATE: Feb 26, 2015",
regex = /^DATE:\s*(.*),\s*(.*)$/;
if (regex.match(input)) {
console.log('Matches Format!');
//.match() needs splicing because .match() returns the actually selected stuff. It becomes weirder with //g
var results = input.match(regex).splice(0,1);
console.log(results);
//Logs: ["Feb 26", "2015"]
}
Regex101 can be useful

Remove all dots except the first one from a string

Given a string
'1.2.3.4.5'
I would like to get this output
'1.2345'
(In case there are no dots in the string, the string should be returned unchanged.)
I wrote this
function process( input ) {
var index = input.indexOf( '.' );
if ( index > -1 ) {
input = input.substr( 0, index + 1 ) +
input.slice( index ).replace( /\./g, '' );
}
return input;
}
Live demo: http://jsfiddle.net/EDTNK/1/
It works but I was hoping for a slightly more elegant solution...
There is a pretty short solution (assuming input is your string):
var output = input.split('.');
output = output.shift() + '.' + output.join('');
If input is "1.2.3.4", then output will be equal to "1.234".
See this jsfiddle for a proof. Of course you can enclose it in a function, if you find it necessary.
EDIT:
Taking into account your additional requirement (to not modify the output if there is no dot found), the solution could look like this:
var output = input.split('.');
output = output.shift() + (output.length ? '.' + output.join('') : '');
which will leave eg. "1234" (no dot found) unchanged. See this jsfiddle for updated code.
It would be a lot easier with reg exp if browsers supported look behinds.
One way with a regular expression:
function process( str ) {
return str.replace( /^([^.]*\.)(.*)$/, function ( a, b, c ) {
return b + c.replace( /\./g, '' );
});
}
You can try something like this:
str = str.replace(/\./,"#").replace(/\./g,"").replace(/#/,".");
But you have to be sure that the character # is not used in the string; or replace it accordingly.
Or this, without the above limitation:
str = str.replace(/^(.*?\.)(.*)$/, function($0, $1, $2) {
return $1 + $2.replace(/\./g,"");
});
You could also do something like this, i also don't know if this is "simpler", but it uses just indexOf, replace and substr.
var str = "7.8.9.2.3";
var strBak = str;
var firstDot = str.indexOf(".");
str = str.replace(/\./g,"");
str = str.substr(0,firstDot)+"."+str.substr(1,str.length-1);
document.write(str);
Shai.
Here is another approach:
function process(input) {
var n = 0;
return input.replace(/\./g, function() { return n++ > 0 ? '' : '.'; });
}
But one could say that this is based on side effects and therefore not really elegant.
This isn't necessarily more elegant, but it's another way to skin the cat:
var process = function (input) {
var output = input;
if (typeof input === 'string' && input !== '') {
input = input.split('.');
if (input.length > 1) {
output = [input.shift(), input.join('')].join('.');
}
}
return output;
};
Not sure what is supposed to happen if "." is the first character, I'd check for -1 in indexOf, also if you use substr once might as well use it twice.
if ( index != -1 ) {
input = input.substr( 0, index + 1 ) + input.substr(index + 1).replace( /\./g, '' );
}
var i = s.indexOf(".");
var result = s.substr(0, i+1) + s.substr(i+1).replace(/\./g, "");
Somewhat tricky. Works using the fact that indexOf returns -1 if the item is not found.
Trying to keep this as short and readable as possible, you can do the following:
JavaScript
var match = string.match(/^[^.]*\.|[^.]+/g);
string = match ? match.join('') : string;
Requires a second line of code, because if match() returns null, we'll get an exception trying to call join() on null. (Improvements welcome.)
Objective-J / Cappuccino (superset of JavaScript)
string = [string.match(/^[^.]*\.|[^.]+/g) componentsJoinedByString:''] || string;
Can do it in a single line, because its selectors (such as componentsJoinedByString:) simply return null when sent to a null value, rather than throwing an exception.
As for the regular expression, I'm matching all substrings consisting of either (a) the start of the string + any potential number of non-dot characters + a dot, or (b) any existing number of non-dot characters. When we join all matches back together, we have essentially removed any dot except the first.
var input = '14.1.2';
reversed = input.split("").reverse().join("");
reversed = reversed.replace(\.(?=.*\.), '' );
input = reversed.split("").reverse().join("");
Based on #Tadek's answer above. This function takes other locales into consideration.
For example, some locales will use a comma for the decimal separator and a period for the thousand separator (e.g. -451.161,432e-12).
First we convert anything other than 1) numbers; 2) negative sign; 3) exponent sign into a period ("-451.161.432e-12").
Next we split by period (["-451", "161", "432e-12"]) and pop out the right-most value ("432e-12"), then join with the rest ("-451161.432e-12")
(Note that I'm tossing out the thousand separators, but those could easily be added in the join step (.join(','))
var ensureDecimalSeparatorIsPeriod = function (value) {
var numericString = value.toString();
var splitByDecimal = numericString.replace(/[^\d.e-]/g, '.').split('.');
if (splitByDecimal.length < 2) {
return numericString;
}
var rightOfDecimalPlace = splitByDecimal.pop();
return splitByDecimal.join('') + '.' + rightOfDecimalPlace;
};
let str = "12.1223....1322311..";
let finStr = str.replace(/(\d*.)(.*)/, '$1') + str.replace(/(\d*.)(.*)/, '$2').replace(/\./g,'');
console.log(finStr)
const [integer, ...decimals] = '233.423.3.32.23.244.14...23'.split('.');
const result = [integer, decimals.join('')].join('.')
Same solution offered but using the spread operator.
It's a matter of opinion but I think it improves readability.

Categories

Resources