Regular expression handle multiple matches like one, how to fix? - javascript

I have a regex, and a string that includes some matches for this regex. My regex handle all this matches like it is only one big match (of course I don't want such behaviour), let me show you an example:
My test string (sorry for scribble, but this doesn't matter):
sdfsd -dsf- sdfsdfssdfsfdsfsd -sdfsdf-
my regex in js code:
view.replace(/(\-(.+)\-)/g, '<span style="background-color:yellow">$1</span>');
my result:
sdfsd<span style="background-color:yellow">-dsf- sdfsdfssdfsfdsfsd -sdfsdf-</span>
As you can see each of this strings in the "-" must be enclosed in span, but there is only one span. How I can fix this? (honestly I don't want change my (.+) regex part, which I think might be a problem, but if there is no other way to do this, let me know).
In other words, result must be:
sdfsd<span style="background-color:yellow">-dsf-</span> sdfsdfssdfsfdsfsd <span style="background-color:yellow">-sdfsdf-</span>
Feel free to ask me in the comments, and thanks for your help.

honestly I don't want change my (.+) regex part, which I think might be a problem
Why not, it is actually the source of the problem, you can try the following regex which would work:
/(\-([^-]+)\-)/g
and if you think that dashes - can appear between - and - themselves then you can use the less efficient:
/(\-(.+?)\-)/g
+? causes a lazy match, or in other words after matching the initial -, then .+? matches a single character then it moves control to the following - which tries to match a dash, if it couldn't then .+? reads (consumes) another character from the input and so on until the following - is able to match.

You can try:
view.replace(/-([^-]+)-/g, '<span style="background-color:yellow">$1</span>');

Related

JS RegEx for finding number of lines in a page, separated by form feed \f

I have a use case that requires a plain-text file to have lines to consist of at most 38 characters, and 'pages' to consist of at most 28 lines. To enforce this, I'm using regular expressions. I was able to enforce the line-length without any problems, but the page-length is proving to be much trickier.
After several iterations, I came to the following as a regular expression that I feel should work, but it isn't.
let expression = /(([^\f]*)(\r\n)){29,}\f/;
It simply results in no matches.
If anyone could provide some feedback, I'd greatly appreciate it! - Jacob
Edit 1 - removed code block around second expression, it was probably making my question confusing.
Edit 2 - removed following text, it's not pertinent:
As a comparison, the following expression results in a single match, the entire document. I'm assuming it's matching all lines up until the final
let expression = /(.*(\r\n)){29,}
Edit 3 - So after some thinking, I realized that my issue is due to the initial section of the regex that matches any characters before a newline is including newlines. Therefore, I believe I need to match any characters before a newline EXCEPT (\f\r\n). However, I'm now having trouble implementing this. I tried the following:
let expression = /([^\f^\r^\n]*(\r\n)){29,}\f/;
But it's also not matching. I'm assuming that my negations are wrong...
Edit 4 - I have the following regex that matches each line: let expression = /([^\f\r\n]{0,}(\r\n))/;
This is pretty close to what I want. All I need now is to match any instances of 29 or more lines followed by \f
Thanks for all the help to those who commented, a friend ended up helping me get the final regex
let expression = /([^\f\r\n]*?\r??\n){29,}?\f/;
Edit:
As you clarified more your problem, and provided your updated regex:
/([^\f^\r^\n]*(\r\n)){29,}\f/;
Your negations are not right here, use [^\f\r\n] instead of [^\f^\r^\n]. This will negate all of \f, \r, and \n.
So, your regex becomes:
/([^\f\r\n]*(\r\n)){29,}\f/;
This will match 29 or more lines of characters (that can be anything but \f, \r or \n), the whole thing followed by a single \f.
Original answer:
Your current regular expression:
let expression = /(([^\f]*)(\r\n)){29,}\f/;
Matches strings that consist of 29 or more lines (separated by \r\n), the whole thing followed by one single \f.
As far as I understood, you want each of your lines to end with \f. Did you mean to include the \f inside?
let expression = /(([^\f]*)(\r\n\f)){29,}/;

Regex testing for special characters

I'm trying to write a regex to test for certain special characters, but I think I am overcomplicating things. The characters I need to check for are: &<>'"
My current regex looks like such:
/&<>'"/
Another I was trying is:
/\&\<\>\'\"/
Any tips for a beginner (in regards to regex)? Thanks!
You are looking for a character class:
/[&<>'"]/
In doing so, any of the characters in the square brackets will be matched.
The expression you were originally using, /&<>'"/, wasn't working as expected because it matches the characters in that sequential order. In other words, it would match a full string such as &<>'" but not &<.
I'm assuming that you want to be able to match all of the characters you listed, at one time.
If so, you should be able to combine a character set with the g (global-matching) flag, for your regex.
Here's what it could look like:
/[<>&'"]/g
Try /(\&|\<|>|\'|\")/
it depends on what regex system you use

Combining 2 regexes, one with exact match using OR operator

I am trying to combine:
^[a-zA-Z.][a-zA-Z'\\- .]*$
with
(\W|^)first\sname(\W|$)
which should check for the exact phrase, first name, if that is correct. It should match either the first regex OR the second exact match. I tried this, but appears invalid:
^(([a-zA-Z.][a-zA-Z'\\- .]*$)|((\W|^)first\sname(\W|$))
This is in javascript btw.
Combining regular expressions generally can be done simply in the following way:
Regex1 + Regex2 = (Regex1|Regex2)
^[a-zA-Z.][a-zA-Z'\\- .]*$
+ (\W|^)first\sname(\W|$) =
(^[a-zA-Z.][a-zA-Z'\\- .]*$|(\W|^)first\sname(\W|$))
Because some SO users have a hard time understand the math analogy, here's a full word explanation.
If you have a regex with content REGEX1 and a second regex with content REGEX2 and you want to combine them in the way that was described by OP in his question, a simple way to do this without optimization is the following.
(REGEX1|REGEX2)
Where you surround both regular expressions with parenthesis and divide the two with |.
Your regex would be the following:
(^[a-zA-Z.][a-zA-Z'\\- .]*$|(\W|^)first\sname(\W|$))
Your first regex has an error in it, though, that makes it invalid. Try this instead.
(^[a-zA-Z.][a-zA-Z'\- .]*$|(\W|^)first\sname(\W|$))
You had \\ in the second character class where you wanted \
The problem is that the first regex is messed up. You don't need to double escape characters. Therefore
\\-
Will match an ascii character between \(92) and (32). Remove one of the slashes.
Reference

Unable to find a string matching a regex pattern

While trying to submit a form a javascript regex validation always proves to be false for a string.
Regex:- ^(([a-zA-Z]:)|(\\\\{2}\\w+)\\$?)(\\\\(\\w[\\w].*))+(.jpeg|.JPEG|.jpg|.JPG)$
I have tried following strings against it
abc.jpg,
abc:.jpg,
a:.jpg,
a:asdas.jpg,
What string could possible match this regex ?
This regex won't match against anything because of that $? in the middle of the string.
Apparently using the optional modifier ? on the end string symbol $ is not correct (if you paste it on https://regex101.com/ it will give you an error indeed). If the javascript parser ignores the error and keeps the regex as it is this still means you are going to match an end string in the middle of a string which is supposed to continue.
Unescaped it was supposed to match a \$ (dollar symbol) but as it is written it won't work.
If you want your string to be accepted at any cost you can probably use Firebug or a similar developer tool and edit the string inside the javascript code (this, assuming there's no server side check too and assuming it's not wrong aswell). If you ignore the $? then a matching string will be \\\\w\\\\ww.jpg (but since the . is unescaped even \\\\w\\\\ww%jpg is a match)
Of course, I wrote this answer assuming the escaping is indeed the one you showed in the question. If you need to find a matching pattern for the correctly escaped one ^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))+(\.jpeg|\.JPEG|\.jpg|\.JPG)$ then you can use this tool to find one http://fent.github.io/randexp.js/ (though it will find weird matches). A matching pattern is c:\zz.jpg
If you are just looking for a regular expression to match what you got there, go ahead and test this out:
(\w+:?\w*\.[jpe?gJPE?G]+,)
That should match exactly what you are looking for. Remove the optional comma at the end if you feel like it, of course.
If you remove escape level, the actual regex is
^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))+(.jpeg|.JPEG|.jpg|.JPG)$
After ^start the first pipe (([a-zA-Z]:)|(\\{2}\w+)\$?) which matches an alpha followed by a colon or two backslashes followed by one or more word characters, followed by an optional literal $. There is some needless parenthesis used inside.
The second part (\\(\w[\w].*))+ matches a backslash, followed by two word characters \w[\w] which looks weird because it's equivalent to \w\w (don't need a character class for second \w). Followed by any amount of any character. This whole thing one or more times.
In the last part (.jpeg|.JPEG|.jpg|.JPG) one probably forgot to escape the dot for matching a literal. \. should be used. This part can be reduced to \.(JPE?G|jpe?g).
It would match something like
A:\12anything.JPEG
\\1$\anything.jpg
Play with it at regex101. A better readable could be
^([a-zA-Z]:|\\{2}\w+\$?)(\\\w{2}.*)+\.(jpe?g|JPE?G)$
Also read the explanation on regex101 to understand any pattern, it's helpful!

Javascript Regex: how to simulate "match without capture" behavior of positive lookbehind?

I have a relatively simple regex problem - I need to match specific words in a string, if they are entire words or a prefix. With word boundaries, it would look something like this:
\b(word1|word2|prefix1|prefix2)
However, I can't use the word boundary condition because some words may start with odd characters, e.g. .999
My solution was to look for whitespace or starting token for these odd cases.
(\b|^|\s)(word1|word2|prefix1|prefix2)
Now words like .999 will still get matched correctly, BUT it also captures the whitespace preceding the matched words/prefixes. For my purposes, I can't have it capture the whitespace.
Positive lookbehinds seem to solve this, but javascript doesn't support them. Is there some other way I can get the same behavior to solve this problem?
You can use a non-capturing group using (?:):
/(?:\b|^|\s)(word1|word2|prefix1|prefix2)/
UPDATE:
Based on what you want to replace it with (and #AlanMoore's good point about the \b), you probably want to go with this:
var regex = /(^|\s)(word1|word2|prefix1|prefix2)/g;
myString.replace(regex,"$1<span>$2</span>");
Note that I changed the first group back to a capturing one since it'll be part of the match but you want to keep it in the replacement string (right?). Also added the g modifier so that this happens for all occurrences in the string (assuming thats what you wanted).
Let's get the terminology straight first. A regex normally consumes everything it matches. When you do a replace(), everything that was consumed is overwritten. You can also capture parts of the matched text separately and plug them back in using $1, $2, etc.
When you were using the word boundary you didn't have to worry about this, because \b doesn't consume anything. But now you're consuming the leading whitespace character if there is one, so you have to plug it back in. I don't know what you're replacing the match with, so I'll just replace them with nothing for this demonstration.
result = subject.replace(/(^|\s)(word1|word2|prefix1|prefix2)/g, "$1");
Note that the \b isn't needed any more. In fact, you must remove it, or it will match things like .999 in xyz.999, because \b matches between z and .. I'm pretty sure you don't want that.

Categories

Resources