Regex multiple matches for HTML attributes - javascript

I want to match multiple data-i18n attributes with a JavaScript regexp.
I tried the following regexp :
var regexp = /(data\-i18n="[^"]+")/g;
which in my head seemed rather straight forward, but it ended up not working.
If you try to match on the following HTML tag :
<a random-attr="ok" data-i18n="first match" data-i18n="second match">my text</a>
doing an exec like this :
/(data\-i18n="[^"]+")/g.exec('<a random-attr="ok" data-i18n="first match" data-i18n="second match">my text</a>')
will raise the following issue :
There are two matches, but they are actually duplicate matches.
The result is :
[ 'data-i18n="first match"',
'data-i18n="first match"',
index: 20,
input: '<a random-attr="ok" data-i18n="first match" data-i18n="second match">my text</a>' ]
Any ideas on how to have multiple matches for my attribute ?
Thanks in advance !

The problem isn't with your regex; its with how you're expecting exec to behave. The return value of exec has the full match at position 0, and then the match of each capture group following that. Since you wrapped the whole regex in a capturing group, you're seeing the same string at positions 0 and 1 of the array.
The right way to use a global regex with exec is to keep calling exec until it returns null; it will return the next match each time. However, if you use String.match(Regexp), it will return what you expect - an array containing all of the matches.

Related

javascript regex insert new element into expression

I am passing a URL to a block of code in which I need to insert a new element into the regex. Pretty sure the regex is valid and the code seems right but no matter what I can't seem to execute the match for regex!
//** Incoming url's
//** url e.g. api/223344
//** api/11aa/page/2017
//** Need to match to the following
//** dir/api/12ab/page/1999
//** Hence the need to add dir at the front
var url = req.url;
//** pass in: /^\/api\/([a-zA-Z0-9-_~ %]+)(?:\/page\/([a-zA-Z0-9-_~ %]+))?$/
var re = myregex.toString();
//** Insert dir into regex: /^dir\/api\/([a-zA-Z0-9-_~ %]+)(?:\/page\/([a-zA-Z0-9-_~ %]+))?$/
var regVar = re.substr(0, 2) + 'dir' + re.substr(2);
var matchedData = url.match(regVar);
matchedData === null ? console.log('NO') : console.log('Yay');
I hope I am just missing the obvious but can anyone see why I can't match and always returns NO?
Thanks
Let's break down your regex
^\/api\/ this matches the beginning of a string, and it looks to match exactly the string "/api"
([a-zA-Z0-9-_~ %]+) this is a capturing group: this one specifically will capture anything inside those brackets, with the + indicating to capture 1 or more, so for example, this section will match abAB25-_ %
(?:\/page\/([a-zA-Z0-9-_~ %]+)) this groups multiple tokens together as well, but does not create a capturing group like above (the ?: makes it non-captuing). You are first matching a string exactly like "/page/" followed by a group exactly like mentioned in the paragraph above (that matches a-z, A-Z, 0-9, etc.
?$ is at the end, and the ? means capture 0 or more of the precending group, and the $ matches the end of the string
This regex will match this string, for example: /api/abAB25-_ %/page/abAB25-_ %
You may be able to take advantage of capturing groups, however, and use something like this instead to get similar results: ^\/api\/([a-zA-Z0-9-_~ %]+)\/page\/\1?$. Here, we are using \1 to reference that first capturing group and match exactly the same tokens it is matching. EDIT: actually, this probably won't work, since the text after /api/ and the text after /page/ will most likely be different, carrying on...
Afterwards, you are are adding "dir" to the beginning of your search, so you can now match someting like this: dir/api/abAB25-_ %/page/abAB25-_ %
You have also now converted the regex to a string, so like Crayon Violent pointed out in their comment, this will break your expected funtionality. You can fix this by using .source on your regex: var matchedData = url.match(regVar.source); https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source
Now you can properly match a string like this: dir/api/11aa/page/2017 see this example: https://repl.it/Mj8h
As mentioned by Crayon Violent in the comments, it seems you're passing a String rather than a regular expression in the .match() function. maybe try the following:
url.match(new RegExp(regVar, "i"));
to convert the string to a regular expression. The "i" is for ignore case; don't know that's what you want. Learn more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

Regular expression to match a string which is NOT matched by a given regexp

I've been hoving around by some answers here, and I can't find a solution to my problem:
I have this regexp which matches everyting inside an HTML span tag, including contents:
<span\b[^>]*>(.*?)</span>
and I want to find a way to make a search in all the text, except for what is matched with that regexp.
For example, if my text is:
var text = "...for there is a class of <span class="highlight">guinea</span> pigs which..."
... then the regexp would match:
<span class="highlight">guinea</span>
and I want to be able to make a regexp such that if I search for "class", regexp will match "...for there is a class of..."
and will not match inside the tag, like in
"... class="highlight"..."
The word to be matched ("class") might be anywhere within the text. I've tried
(?!<span\b[^>]*>(.*?)</span>)class
but it keeps searching inside tags as well.
I want to find a solution using only regexp, not dealing with DOM nor JQuery. Thanks in advance :).
Although I wouldn't recommend this, I would do something like below
(class)(?:(?=.*<span\b[^>]*>))|(?:(?<=<\/span>).*)(class)
You can see this in action here
Rubular Link for this regex
You can capture your matches from the groups and work with them as needed. If you can, use a HTML parser and then find matches from the text element.
It's not pretty, but if I get you right, this should do what you wan't. It's done with a single RegEx but js can't (to my knowledge) extract the result without joining the results in a loop.
The RegEx: /(?:<span\b[^>]*>.*?<\/span>)|(.)/g
Example js code:
var str = '...for there is a class of <span class="highlight">guinea</span> pigs which...',
pattern = /(?:<span\b[^>]*>.*?<\/span>)|(.)/g,
match,
res = '';
match = pattern.exec(str)
while( match != null )
{
res += match[1];
match = pattern.exec(str)
}
document.writeln('Result:' + res);
In English: Do a non capturing test against your tag-expression or capture any character. Do this globally to get the entire string. The result is a capture group for each character in your string, except the tag. As pointed out, this is ugly - can result in a serious number of capture groups - but gets the job done.
If you need to send it in and retrieve the result in one call, I'd have to agree with previous contributors - It can't be done!

Extract specific chars from a string using a regex

I need to split an email address and take out the first character and the first character after the '#'
I can do this as follows:
'bar#foo'.split('#').map(function(a){ return a.charAt(0); }).join('')
--> bf
Now I was wondering if it can be done using a regex match, something like this
'bar#foo'.match(/^(\w).*?#(\w)/).join('')
--> bar#fbf
Not really what I want, but I'm sure I miss something here! Any suggestions ?
Why use a regex for this? just use indexOf to get the char at any given position:
var addr = 'foo#bar';
console.log(addr[0], addr[addr.indexOf('#')+1])
To ensure your code works on all browsers, you might want to use charAt instead of []:
console.log(addr.charAt(0), addr.charAt(addr.indexOf('#')+1));
Either way, It'll work just fine, and This is undeniably the fastest approach
If you are going to persist, and choose a regex, then you should realize that the match method returns an array containing 3 strings, in your case:
/^(\w).*?#(\w)/
["the whole match",//start of string + first char + .*?# + first string after #
"groupw 1 \w",//first char
"group 2 \w"//first char after #
]
So addr.match(/^(\w).*?#(\w)/).slice(1).join('') is probably what you want.
If I understand correctly, you are quite close. Just don't join everything returned by match because the first element is the entire matched string.
'bar#foo'.match(/^(\w).*?#(\w)/).splice(1).join('')
--> bf
Using regex:
matched="",
'abc#xyz'.replace(/(?:^|#)(\w)/g, function($0, $1) { matched += $1; return $0; });
console.log(matched);
// ax
The regex match function returns an array of all matches, where the first one is the 'full text' of the match, followed by every sub-group. In your case, it returns this:
bar#f
b
f
To get rid of the first item (the full match), use slice:
'bar#foo'.match(/^(\w).*?#(\w)/).slice(1).join('\r')
Use String.prototype.replace with regular expression:
'bar#foo'.replace(/^(\w).*#(\w).*$/, '$1$2'); // "bf"
Or using RegEx
^([a-zA-Z0-9])[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+#([a-zA-Z0-9-])[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$
Fiddle

Regex thinks I'm nesting, but I'm not

I wrote this regexp to capture the strings below.
\!\[(.*?)?\]
All the strings below should match and return an optional string that's inside the first set of square brackets.
![]
![caption]
![]()
![caption]()
![caption][]
The problem is that this string also matches and returns ][ because the regex thinks it's between the first [ and last ].
![][] // Should not match, but does and returns "]["
How do I fix this?
Just remove the ? outside (.*?), that is redundant.
var myArray = ["![abc]","![caption]", "![def]()", "![caption]()","![caption][]"];
myArray.forEach(function(current) {
console.log(/!\[(.*?)\]/.exec(current)[1]);
});
Output
abc
caption
def
caption
caption
Check how the RegEx works here
Use this regex:
\!\[([^\]]*)\]
It means that it expects a "last" ] but makes internal ones invalid.
This should solve your issue.
My preference is this if you want to ignore catching the things like this ![[]]
\!\[([^\[\]]*)\]

Replace all besides the Regex group?

I was given a task to do which requires a long time to do.
The image say it all :
This is what I have : (x100 times):
And I need to extract this value only
How can I capture the value ?
I have made it with this regex :
DbCommand.*?\("(.*?)"\);
As you can see it does work :
And after the replace function (replace to $1) I do get the pure value :
but the problem is that I need only the pure values and not the rest of the unmatched group :
Question : In other words :
How can I get the purified result like :
Eservices_Claims_Get_Pending_Claims_List
Eservices_Claims_Get_Pending_Claims_Step1
Here is my code at Online regexer
Is there any way of replacing "all besides the matched group" ?
p.s. I know there are other ways of doing it but I prefer a regex solution ( which will also help me to understand regex better)
Unfortunately, JavaScript doesn't understand lookbehind. If it did, you could change your regular expression to match .*? preceded (lookbehind) by DbCommand.*?\(" and followed (lookahead) by "\);.
With that solution denied, i believe the cleanest solution is to perform two matches:
// you probably want to build the regexps dynamically
var regexG = /DbCommand.*?\("(.*?)"\);/g;
var regex = /DbCommand.*?\("(.*?)"\);/;
var matches = str.match(regexG).map(function(item){ return item.match(regex)[1] });
console.log(matches);
// ["Eservices_Claims_Get_Pending_Claims_List", "Eservices_Claims_Get_Pending_Claims_Step1"]
DEMO: http://jsbin.com/aqaBobOP/2/edit
You should be able to do a global replace of:
public static DataTable.*?{.*?DbCommand.*?\("(.*?)"\);.*?}
All I've done is changed it to match the whole block including the function definition using a bunch of .*?s.
Note: Make sure your regex settings are such that the dot (.) matches all characters, including newlines.
In fact if you want to close up all whitespace, you can slap a \s* on the front and replace with $1\n:
\s*public static DataTable.*?{.*?DbCommand.*?\("(.*?)"\);.*?}
Using your test case: http://regexr.com?37ibi
You can use this (without the ignore case and multiline option, with a global search):
pattern: (?:[^D]+|\BD|D(?!bCommand ))+|DbCommand [^"]+"([^"]+)
replace: $1\n
Try simply replacing the whole document replacing using this expression:
^(?: |\t)*(?:(?!DbCommand).)*$
You will then only be left with the lines that begin with the string DbCommand
You can then remove the spaces in between by replacing:
\r?\n\s* with \n globally.
Here is an example of this working: http://regexr.com?37ic4

Categories

Resources