javascript Reg Backwards not works - javascript

I want to match a number in a string:
'abc#2003, or something else #2017'
I want to get result [2003, 2007] with match function.
let strReg = 'abc#2003, or something else #2017';
let reg = new RegExp(/(?=(#\d+))\1/);
strReg.match(reg) //[ '#2003 ', '#2017 ' ]
let reg1 = new RegExp(/(?=#(\d+))\1/)
strReg.match(reg1) //null, but I expect [2003, 2007]
the result mains '\1' match after '?=', ?=()\1 works, ?=#()\1 not.
javascript only supports backwards, how should I do to match '#' but ignore it?

I take it that you want an array of the results, so...
var s = "abc#2003, or something else #2017 not the 2001 though";
var re = /#(\d+)/g;
var result = [];
var match = re.exec(s);
while (match !== null) {
result.push(parseInt(match[1]));
match = re.exec(s);
}
console.log(result);
Outputs:
Array [ 2003, 2017 ]
match(0) is the entire match, match(1) is the captured group.
Also, see How do you access the matched groups in a JavaScript regular expression?
Inspired by javascript regex - look behind alternative?, if you want to do it as almost a one-liner:
var re = /(\d+)(?=#)/g; /* write the regex backwards */
var result = [];
s.split('').reverse().join('').match(re).forEach(function (el) { result.push(parseInt(el.split('').reverse().join(''))); });
console.log(result.reverse());
Caveat: Who wrote this programing saying? “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”

Small change to your code does the job as follows:
/#(\d+)/g
number followed by # will be remembered as you required.

Related

JS What's the fastest way to display one specific line of a list?

In my Javascript code, I get one very long line as a string.
This one line only has around 65'000 letters. Example:
config=123&url=http://localhost/example&path_of_code=blablaba&link=kjslfdjs...
What I have to do is replace all & with an break (\n) first and then pick only the line which starts with "path_of_code=". This line I have to write in a variable.
The part with replace & with an break (\n) I already get it, but the second task I didn't.
var obj = document.getElementById('div_content');
var contentJS= obj.value;
var splittedResult;
splittedResult = contentJS.replace(/&/g, '\n');
What is the fastest way to do it? Please note, the list is usually very long.
It sounds like you want to extract the text after &path_of_code= up until either the end of the string or the next &. That's easily done with a regular expression using a capture group, then using the value of that capture group:
var rex = /&path_of_code=([^&]+)/;
var match = rex.exec(theString);
if (match) {
var text = match[1];
}
Live Example:
var theString = "config=123&url=http://localhost/example&path_of_code=blablaba&link=kjslfdjs...";
var rex = /&path_of_code=([^&]+)/;
var match = rex.exec(theString);
if (match) {
var text = match[1];
console.log(text);
}
Use combination of String.indexOf() and String.substr()
var contentJS= "123&url=http://localhost/example&path_of_code=blablaba&link=kjslfdjs...";
var index = contentJS.indexOf("&path_of_code"),
substr = contentJS.substr(index+1),
res = substr.substr(0, substr.indexOf("&"));
console.log(res)
but the second task I didn't.
You can use filter() and startsWith()
splittedResult = splittedResult.filter(i => i.startsWith('path_of_code='));

Develop vscode extension for replace text

I have a list of data that I need to put a ' symbol at the start of the line and at the end of the line. So the original data look like
11223334444xxx55555
11xxx223334444555xxx55
11xxxx22333444xxx455555
11xxxxx22333444455555
11xxxxxx223334444555xxx55
and I want all the line to look like
11223334444yyyy55555
11yyyy223334444555yyyy55
11yyyyx22333444yyyy455555
11yyyyxx22333444455555
11yyyyyyyy223334444555yyyy55
that is 'yyyy' replace 'xxx', how I write my code? Both typescript and javascript are perfect.
Sorry, my bad. I want develop an extension to do it, and above just an example. Many answers below just miss select full text part.
const textEditor = vscode.window.activeTextEditor;
if (!textEditor) {
return; // No open text editor
}
var firstLine = textEditor.document.lineAt(0);
var lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
var textRange = new vscode.Range(0,
firstLine.range.start.character,
textEditor.document.lineCount - 1,
lastLine.range.end.character);
textEditor.edit(function (editBuilder) {
editBuilder.replace(textRange, '$1');
});
});
replace function above just has one replace argument, not two, how can I replace it?
Try this:
let checkD =
11223334444xxx55555
11xxx223334444555xxx55
11xxxx22333444xxx455555
11xxxxx22333444455555
11xxxxxx223334444555xxx55
;
checkD.replace(/xxx/g, 'yyyy');
You can try it with regex. Read more at the MDN.
Here is an array example:
let data = [
"11223334444xxx55555",
"11xxx223334444555xxx55",
"11xxxx22333444xxx455555",
"11xxxxx22333444455555",
"11xxxxxx223334444555xxx55"
];
let max = data.length;
for (let i = 0; i < max; i++) {
let regex = new RegExp("xxx", "g")
data[i] = data[i].replace(regex, "yyyy")
}
console.log(data);
Here is a single string example:
let data = `11223334444xxx55555
11xxx223334444555xxx55
11xxxx22333444xxx455555
11xxxxx22333444455555
11xxxxxx223334444555xxx55`;
let regex = new RegExp("xxx", "g")
data = data.replace(regex, "yyyy")
console.log(data);
I know it's late, but I was struggling with this sort of an issue and got myself to resolve it, using JS.
If I understood your question right.
You want to replace three 'x' letters with four 'y' letters.
I.e., turn this
xxxxxx1xxx2xx into this yyyyyyyy1yyyy2xx
const textEditor = vscode.window.activeTextEditor;
if (!textEditor) {
vscode.window.showErrorMessage("Editor Does Not Exist");
return;
}
var m;
let fullText = editor.document.getText();
const regex = /xxx/gm; // 'g' flag is for global search & 'm' flag is for multiline.
//searching for previously declared xxx in regex and replacing it with 'yyyy'.
let textReplace = fullText.replace(regex, `yyyy`);
//Creating a new range with startLine, startCharacter & endLine, endCharacter.
let invalidRange = new vscode.Range(0, 0, editor.document.lineCount, 0);
// To ensure that above range is completely contained in this document.
let validFullRange = editor.document.validateRange(invalidRange);
while ((m = regex.exec(fullText)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
editor.edit(editBuilder => {
editBuilder.replace(validFullRange, textReplace);
}).catch(err => console.log(err));
}
Regexp g flag is for global search to match all occurrences, without it, it'll only check for the first.
Regexp m flag is for multiline, it makes ^ and $ match at line beginnings and line endings(instead of at string), respectively.
Reference: global - JavaScript | MDN ,
multiline - JavaScript | MDN
Also, consider looking at the VSCode API Doc for Range & Validate Range
that is 'yyyy' replace 'xxx', how I write my code
split and join is what I use e.g.
str.split('yyyy').join('xxx');

Regex remove repeated characters from a string by javascript

I have found a way to remove repeated characters from a string using regular expressions.
function RemoveDuplicates() {
var str = "aaabbbccc";
var filtered = str.replace(/[^\w\s]|(.)\1/gi, "");
alert(filtered);
}
Output: abc
this is working fine.
But if str = "aaabbbccccabbbbcccccc" then output is abcabc.
Is there any way to get only unique characters or remove all duplicates one?
Please let me know if there is any way.
A lookahead like "this, followed by something and this":
var str = "aaabbbccccabbbbcccccc";
console.log(str.replace(/(.)(?=.*\1)/g, "")); // "abc"
Note that this preserves the last occurrence of each character:
var str = "aabbccxccbbaa";
console.log(str.replace(/(.)(?=.*\1)/g, "")); // "xcba"
Without regexes, preserving order:
var str = "aabbccxccbbaa";
console.log(str.split("").filter(function(x, n, s) {
return s.indexOf(x) == n
}).join("")); // "abcx"
This is an old question, but in ES6 we can use Sets. The code looks like this:
var test = 'aaabbbcccaabbbcccaaaaaaaasa';
var result = Array.from(new Set(test)).join('');
console.log(result);

How can I split this string in JavaScript?

I have strings like this:
ab
rx'
wq''
pok'''
oyu,
mi,,,,
Basically, I want to split the string into two parts. The first part should have the alphabetical characters intact, the second part should have the non-alphabetical characters.
The alphabetical part is guaranteed to be 2-3 lowercase characters between a and z; the non-alphabetical part can be any length, and is gauranteed to only be the characters , or ', but not both in the one string (e.g. eex,', will never occur).
So the result should be:
[ab][]
[rx][']
[wq]['']
[pok][''']
[oyu][,]
[mi][,,,,]
How can I do this? I'm guessing a regular expression but I'm not particularly adept at coming up with them.
Regular expressions have is a nice special called "word boundary" (\b). You can use it, well, to detect the boundary of a word, which is a sequence of alpha-numerical characters.
So all you have to do is
foo.split(/\b/)
For example,
"pok'''".split(/\b/) // ["pok", "'''"]
If you can 100% guarantee that:
Letter-strings are 2 or 3 characters
There are always one or more primes/commas
There is never any empty space before, after or in-between the letters and the marks
(aside from line-break)
You can use:
/^([a-zA-Z]{2,3})('+|,+)$/gm
var arr = /^([a-zA-Z]{2,3})('+|,+)$/gm.exec("pok'''");
arr === ["pok'''", "pok", "'''"];
var arr = /^([a-zA-Z]{2,3})('+|,+)$/gm.exec("baf,,,");
arr === ["baf,,,", "baf", ",,,"];
Of course, save yourself some sanity, and save that RegEx as a var.
And as a warning, if you haven't dealt with RegEx like this:
If a match isn't found -- if you try to match foo','' by mixing marks, or you have 0-1 or 4+ letters, or 0 marks... ...then instead of getting an array back, you'll get null.
So you can do this:
var reg = /^([a-zA-Z]{2,3})('+|,+)$/gm,
string = "foobar'',,''",
result_array = reg.exec(string) || [string];
In this case, the result of the exec is null; by putting the || (or) there, we can return an array that has the original string in it, as index-0.
Why?
Because the result of a successful exec will have 3 slots; [*string*, *letters*, *marks*].
You might be tempted to just read the letters like result_array[1].
But if the match failed and result_array === null, then JavaScript will scream at you for trying null[1].
So returning the array at the end of a failed exec will allow you to get result_array[1] === undefined (ie: there was no match to the pattern, so there are no letters in index-1), rather than a JS error.
You could try something like that:
function splitString(string){
var match1 = null;
var match2 = null;
var stringArray = new Array();
match1 = string.indexOf(',');
match2 = string.indexOf('`');
if(match1 != 0){
stringArray = [string.slice(0,match1-1),string.slice(match1,string.length-1];
}
else if(match2 != 0){
stringArray = [string.slice(0,match2-1),string.slice(match2,string.length-1];
}
else{
stringArray = [string];
}
}
var str = "mi,,,,";
var idx = str.search(/\W/);
if(idx) {
var list = [str.slice(0, idx), str.slice(idx)]
}
You'll have the parts in list[0] and list[1].
P.S. There might be some better ways than this.
yourStr.match(/(\w{2,3})([,']*)/)
if (match = string.match(/^([a-z]{2,3})(,+?$|'+?$)/)) {
match = match.slice(1);
}

RegEx to extract all matches from string using RegExp.exec

I'm trying to parse the following kind of string:
[key:"val" key2:"val2"]
where there are arbitrary key:"val" pairs inside. I want to grab the key name and the value.
For those curious I'm trying to parse the database format of task warrior.
Here is my test string:
[description:"aoeu" uuid:"123sth"]
which is meant to highlight that anything can be in a key or value aside from space, no spaces around the colons, and values are always in double quotes.
In node, this is my output:
[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
'uuid',
'123sth',
index: 0,
input: '[description:"aoeu" uuid:"123sth"]' ]
But description:"aoeu" also matches this pattern. How can I get all matches back?
Continue calling re.exec(s) in a loop to obtain all the matches:
var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
var m;
do {
m = re.exec(s);
if (m) {
console.log(m[1], m[2]);
}
} while (m);
Try it with this JSFiddle: https://jsfiddle.net/7yS2V/
str.match(pattern), if pattern has the global flag g, will return all the matches as an array.
For example:
const str = 'All of us except #Emran, #Raju and #Noman were there';
console.log(
str.match(/#\w*/g)
);
// Will log ["#Emran", "#Raju", "#Noman"]
To loop through all matches, you can use the replace function:
var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
s.replace(re, function(match, g1, g2) { console.log(g1, g2); });
This is a solution
var s = '[description:"aoeu" uuid:"123sth"]';
var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
console.log(m[1], m[2]);
}
This is based on lawnsea's answer, but shorter.
Notice that the `g' flag must be set to move the internal pointer forward across invocations.
str.match(/regex/g)
returns all matches as an array.
If, for some mysterious reason, you need the additional information comes with exec, as an alternative to previous answers, you could do it with a recursive function instead of a loop as follows (which also looks cooler :).
function findMatches(regex, str, matches = []) {
const res = regex.exec(str)
res && matches.push(res) && findMatches(regex, str, matches)
return matches
}
// Usage
const matches = findMatches(/regex/g, str)
as stated in the comments before, it's important to have g at the end of regex definition to move the pointer forward in each execution.
We are finally beginning to see a built-in matchAll function, see here for the description and compatibility table. It looks like as of May 2020, Chrome, Edge, Firefox, and Node.js (12+) are supported but not IE, Safari, and Opera. Seems like it was drafted in December 2018 so give it some time to reach all browsers, but I trust it will get there.
The built-in matchAll function is nice because it returns an iterable. It also returns capturing groups for every match! So you can do things like
// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);
for (match of matches) {
console.log("letter before:" + match[1]);
console.log("letter after:" + match[2]);
}
arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array
It also seem like every match object uses the same format as match(). So each object is an array of the match and capturing groups, along with three additional properties index, input, and groups. So it looks like:
[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]
For more information about matchAll there is also a Google developers page. There are also polyfills/shims available.
If you have ES9
(Meaning if your system: Chrome, Node.js, Firefox, etc supports Ecmascript 2019 or later)
Use the new yourString.matchAll( /your-regex/g ).
If you don't have ES9
If you have an older system, here's a function for easy copy and pasting
function findAll(regexPattern, sourceString) {
let output = []
let match
// auto-add global flag while keeping others as-is
let regexPatternWithGlobal = RegExp(regexPattern,[...new Set("g"+regexPattern.flags)].join(""))
while (match = regexPatternWithGlobal.exec(sourceString)) {
// get rid of the string copy
delete match.input
// store the match data
output.push(match)
}
return output
}
example usage:
console.log( findAll(/blah/g,'blah1 blah2') )
outputs:
[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]
Based on Agus's function, but I prefer return just the match values:
var bob = "> bob <";
function matchAll(str, regex) {
var res = [];
var m;
if (regex.global) {
while (m = regex.exec(str)) {
res.push(m[1]);
}
} else {
if (m = regex.exec(str)) {
res.push(m[1]);
}
}
return res;
}
var Amatch = matchAll(bob, /(&.*?;)/g);
console.log(Amatch); // yeilds: [>, <]
Iterables are nicer:
const matches = (text, pattern) => ({
[Symbol.iterator]: function * () {
const clone = new RegExp(pattern.source, pattern.flags);
let match = null;
do {
match = clone.exec(text);
if (match) {
yield match;
}
} while (match);
}
});
Usage in a loop:
for (const match of matches('abcdefabcdef', /ab/g)) {
console.log(match);
}
Or if you want an array:
[ ...matches('abcdefabcdef', /ab/g) ]
Here is my function to get the matches :
function getAllMatches(regex, text) {
if (regex.constructor !== RegExp) {
throw new Error('not RegExp');
}
var res = [];
var match = null;
if (regex.global) {
while (match = regex.exec(text)) {
res.push(match);
}
}
else {
if (match = regex.exec(text)) {
res.push(match);
}
}
return res;
}
// Example:
var regex = /abc|def|ghi/g;
var res = getAllMatches(regex, 'abcdefghi');
res.forEach(function (item) {
console.log(item[0]);
});
If you're able to use matchAll here's a trick:
Array.From has a 'selector' parameter so instead of ending up with an array of awkward 'match' results you can project it to what you really need:
Array.from(str.matchAll(regexp), m => m[0]);
If you have named groups eg. (/(?<firstname>[a-z][A-Z]+)/g) you could do this:
Array.from(str.matchAll(regexp), m => m.groups.firstName);
Since ES9, there's now a simpler, better way of getting all the matches, together with information about the capture groups, and their index:
const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
console.log(match);
}
// ["mice", index: 0, input: "mice like to dice rice", groups:
undefined]
// ["dice", index: 13, input: "mice like to dice rice",
groups: undefined]
// ["rice", index: 18, input: "mice like to dice
rice", groups: undefined]
It is currently supported in Chrome, Firefox, Opera. Depending on when you read this, check this link to see its current support.
Use this...
var all_matches = your_string.match(re);
console.log(all_matches)
It will return an array of all matches...That would work just fine....
But remember it won't take groups in account..It will just return the full matches...
I would definatly recommend using the String.match() function, and creating a relevant RegEx for it. My example is with a list of strings, which is often necessary when scanning user inputs for keywords and phrases.
// 1) Define keywords
var keywords = ['apple', 'orange', 'banana'];
// 2) Create regex, pass "i" for case-insensitive and "g" for global search
regex = new RegExp("(" + keywords.join('|') + ")", "ig");
=> /(apple|orange|banana)/gi
// 3) Match it against any string to get all matches
"Test string for ORANGE's or apples were mentioned".match(regex);
=> ["ORANGE", "apple"]
Hope this helps!
This isn't really going to help with your more complex issue but I'm posting this anyway because it is a simple solution for people that aren't doing a global search like you are.
I've simplified the regex in the answer to be clearer (this is not a solution to your exact problem).
var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);
// We only want the group matches in the array
function purify_regex(reResult){
// Removes the Regex specific values and clones the array to prevent mutation
let purifiedArray = [...reResult];
// Removes the full match value at position 0
purifiedArray.shift();
// Returns a pure array without mutating the original regex result
return purifiedArray;
}
// purifiedResult= ["description", "aoeu"]
That looks more verbose than it is because of the comments, this is what it looks like without comments
var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);
function purify_regex(reResult){
let purifiedArray = [...reResult];
purifiedArray.shift();
return purifiedArray;
}
Note that any groups that do not match will be listed in the array as undefined values.
This solution uses the ES6 spread operator to purify the array of regex specific values. You will need to run your code through Babel if you want IE11 support.
Here's a one line solution without a while loop.
The order is preserved in the resulting list.
The potential downsides are
It clones the regex for every match.
The result is in a different form than expected solutions. You'll need to process them one more time.
let re = /\s*([^[:]+):\"([^"]+)"/g
let str = '[description:"aoeu" uuid:"123sth"]'
(str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e))
[ [ 'description:"aoeu"',
'description',
'aoeu',
index: 0,
input: 'description:"aoeu"',
groups: undefined ],
[ ' uuid:"123sth"',
'uuid',
'123sth',
index: 0,
input: ' uuid:"123sth"',
groups: undefined ] ]
My guess is that if there would be edge cases such as extra or missing spaces, this expression with less boundaries might also be an option:
^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$
If you wish to explore/simplify/modify the expression, it's been
explained on the top right panel of
regex101.com. If you'd like, you
can also watch in this
link, how it would match
against some sample inputs.
Test
const regex = /^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$/gm;
const str = `[description:"aoeu" uuid:"123sth"]
[description : "aoeu" uuid: "123sth"]
[ description : "aoeu" uuid: "123sth" ]
[ description : "aoeu" uuid : "123sth" ]
[ description : "aoeu"uuid : "123sth" ] `;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
RegEx Circuit
jex.im visualizes regular expressions:
const re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
const matches = [...re.exec('[description:"aoeu" uuid:"123sth"]').entries()]
console.log(matches)
Basically, this is ES6 way to convert Iterator returned by exec to a regular Array
Here is my answer:
var str = '[me nombre es] : My name is. [Yo puedo] is the right word';
var reg = /\[(.*?)\]/g;
var a = str.match(reg);
a = a.toString().replace(/[\[\]]/g, "").split(','));

Categories

Resources