I have a working regular expression which matches the words below.
Input:
(T1.Test)
(AT.Test)
Match:
T1.Test
AT.Test
But when I try replacing /w with unicode \p{L}, the regex does not work properly anymore.
Current expression: /(?:\w+\()+|\b(\p{L}+(?:\.\p{L}+)?)\b(?!')/gu
Input:
(T1.Test)
(AT.Test)
(ワーク.Test)
Match:
Test
Test
Test
How do I make my regex works properly now it has unicode flag?
My expected output should be:
T1.Test
AT.Test
ワーク.Test
First of all \p{L} does not catch numbers, so (T1.Test) will not be matched, while with \w would be.
Your regex is diveded in two big OR parts "1 | 2":
(?:\w+\()+ this non capturing group is matching anything of the shape anyAmmountOfLetter(. If this has success will totally ignore the rest of the regex, I don't know if it was intentional. This for example will trigger your regex: aaa(333.6780) with aaa( as full match, but 0 groups as you are not capturing it.
\b(\p{L}+(?:\.\p{L}+)?)\b(?!') this requires that you start your expression with a word boundary. But \b is valid in between two characters (Regex Tutorial) only if one is a word character an the other is not.
In your case, your starting round bracket will not be matched against the word boundary so (クーク.Test) will not work, but 3クーク.Test) will.
For fix that you can use only the second part (if the first is not really needed for checking something else of what you had shown in the question inputs):
// slight edited, can use digits: (3123.123) => 3123.123
input.match(/[\b]*\(([\d\p{L}]+(?:\.[\d\p{L}]+)?)\)[\b]*(?!')/gu)
// slight edited, must start with letter: (A1.Test) works, (1A.Test) doesn't
input.match(/[\b]*\((\p{L}[\d\p{L}]*(?:\.[\d\p{L}]+)?)\)[\b]*(?!')/gu)
Also the last part \b(?!') is optional for the input cases you gave, but I suppose it is usefull for other purposes.
If you want to keep the regex simple for those inputs, this would also work:
// can use digits: (3123.123) => 3123.123
input.match(/\(([\p{L}\d]+(?:\.[\p{L}\d]+))\)/gu)
// must start with letter: (A1.Test) works, (1A.Test) doesn't
input.match(/\((\p{L}[\p{L}\d]*(?:\.[\p{L}\d]+))\)/gu)
Related
I have a text and I need to match all text parts except given words with regexp
For example if text is ' Something went wrong and I could not do anything ' and given words are 'and' and 'not' then the result must be ['Something went wrong', 'I could', 'do anything']
Please don't advise me to use string.split() or string.replace() and etc. I know a several ways how I can do this with build-in methods. I'm wonder if there a regex which can do this, when I will execute text.math(/regexp/g)
Please note that the regular expression must work at least in Chrome, Firefox and Safari versions not lower than the current one by 3! At the moment of asking this question the actual versions are 100.0, 98.0.2 and 15.3 respectively. For example you can not use lookbehind feature in Safari
Please, before answering my question, go to https://regexr.com/ and check your answer!. Your regular expression should highlight all parts of a sentence, including spaces between words of need parts and except empty spaces around need parts, except for the given words
Before asking this question I tried to do my own search but this links didn't help me. I also tried non accepted answers:
Match everything except for specified strings
Regex: match everything but a specific pattern
Regex to match all words except a given list
Regex to match all words except a given list (2)
Need to find a regular expression for any word except word1 or word2
Matching all words except one
Javascript match eveything except given words
It's possible with only using match and lookaheads in javascript.
/\b(?=\w)(?!(?:and|not)\b).*?(?=\s+(?:and|not)\b|\s*$)/gi
Test on RegExr here
Basically match the start of a word that's not a restricted word
\b(?=\w)(?!(?:and|not)\b)
Then a lazy match till the next whitespaces and restricted word, or the end of the line without including last whitespaces.
.*?(?=\s+(?:and|not)\b|\s*$)
Test Snippet :
const re = /\b(?=\w)(?!(?:and|not)\b).*?(?=\s+(?:and|not)\b|\s*$)/gi
let str = ` Something went wrong and I could not do anything `;
let arr = str.match(re);
console.log(arr);
See Edit further down.
You can use this regex, which only use look ahead:
/(?!and|not)\b.*?(?=and|not|$)/g
Explanation:
(?!and|not) - negative look ahead for and or not
\b - match word boundary, to prevent matching nd and ot
.*? - match any char zero or more times, as few as possible
(?=and|not|$) - look ahead for and or not or end of text
If your text has multiple lines you can add the m flag (multiline). Alternatively you can replace dot (.) with [\s\S].
Edit:
I have changed it a little so spaces around the forbidden words are removed:
/(?!and|not)\b\w.*?(?= and| not|$)/g
I have added a \w character match to push the start of the match after the space and added spaces in the look ahead.
Edit2: (to handle multiple spaces around words):
You were very close! All you need is a \s* before the dollar sign and specified words:
/(?!and|not|\s)\b.*?(?=\s*(and|not|$))/g
Updated link: regexr.com
I have a regex for a game that should match strings in the form of go [anything] or [cardinal direction], and capture either the [anything] or the [cardinal direction]. For example, the following would match:
go north
go foo
north
And the following would not match:
foo
go
I was able to do this using two separate regexes: /^(?:go (.+))$/ to match the first case, and /^(north|east|south|west)$/ to match the second case. I tried to combine the regexes to be /^(?:go (.+))|(north|east|south|west)$/. The regex matches all of my test cases correctly, but it doesn't correctly capture for the second case. I tried plugging the regex into RegExr and noticed that even though the first case wasn't being matched against, it was still being captured.
How can I correct this?
Try using the positive lookbehind feature to find the word "go".
(north|east|south|west|(?<=go ).+)$
Note that this solution prevents you from including ^ at the start of the regex, because the text "go" is not actually included in the group.
You have to move the closing parenthesis to the end of the pattern to have both patterns between anchors, or else you would allow a match before one of the cardinal directions and it would still capture the cardinal direction at the end of the string.
Then in the JavaScript you can check for the group 1 or group 2 value.
^(?:go (.+)|(north|east|south|west))$
^
Regex demo
Using a lookbehind assertion (if supported), you might also get a match only instead of capture groups.
In that case, you can match the rest of the line, asserting go to the left at the start of the string, or match only 1 of the cardinal directions:
(?<=^go ).+|^(?:north|east|south|west)$
Regex demo
Not quite sure how to go about this, but basically what I want to do is match a character, say a for example. In this case all of the following would not contain matches (i.e. I don't want to match them):
aa
aaa
fooaaxyz
Whereas the following would:
a (obviously)
fooaxyz (this would only match the letter a part)
My knowledge of RegEx is not great, so I am not even sure if this is possible. Basically what I want to do is match any single a that has any other non a character around it (except for the start and end of the string).
Basically what I want to do is match any single a that has any other non a character around it (except for the start and end of the string).
^[^\sa]*\Ka(?=[^\sa]*$)
DEMO
\K discards the previously matched characters and lookahead assertes whether a match is possibel or not. So the above matches only the letter a which satifies the conditions.
OR
a{2,}(*SKIP)(*F)|a
DEMO
You may use a combination of a lookbehind and a lookahead:
(?<!a)a(?!a)
See the regex demo and the regex graph:
Details
(?<!a) - a negative lookbehind that fails the match if, immediately to the left of the current location, there is a a char
a - an a char
(?!a) - a negative lookahead that fails the match if, immediately to the right of the current location, there is a a char.
You need two things:
a negated character class: [^a] (all except "a")
anchors (^ and $) to ensure that the limits of the string are reached (in other words, that the pattern matches the whole string and not only a substring):
Result:
^[^a]*a[^a]*$
Once you know there is only one "a", you can use the way you want to extract/replace/remove it depending of the language you use.
I am having trouble building a very complex Regex. These are my constraints:
Length: 8 to 10
Cannot start by a number neither by an underscore
Has at least one capital letter, one number and one character among
the following 3 special characters: _$£
I thought I did it when I got to this:
^([^0-9_])(?=.*[A-Z])(?=.*[0-9])(?=.*[$£_])[A-Za-z0-9$£_]{7,9}$
It correctly fails the 1st statement:
aDf123_ fails because its length is not 8
aDf123_aAAFF fails because its length is more than 10
It correctly fails the 2nd statement:
_aDf1234 fails because it starts with an underscore
1aDf1234 fails because it starts with a number
It correctly fails the 3rd statement:
aaDf1234 fails because it doesn't have any special character
aadf1$34 fails because it doens't have a capital letter
aaDf$£££ fails because it doesn't have a number
And finally, it passes through the validation with a valid string: aaDf$££5
What is the problem? The problem is that the following string fails while it should pass through the validation: Daaa$444
When the capital letter is the first letter my regex doesn't see it. How can I make it see it? I know it is related with the fact that my regex ends with {7,9} instead of {8,10} but I cannot help it because I have to define that it must not start with a number or underscore...
You need to put lookaheads after ^ and replace [^0-9_] with [A-Za-z$£]:
^(?=.*[A-Z])(?=.*[0-9])(?=.*[$£_])[A-Za-z$£][A-Za-z0-9$£_]{7,9}$
See this regex demo.
Else, the first [^0-9_] matches ^, &, etc. that is NOT a digit or _ and the lookaheads only look for the required patterns after the first char. So, any valid string that has a required char only at its beginning will fail.
Alternatively, turn the [^0-9_] into the negative (?![0-9_]) lookahead (and then you will need to replace the {7,9} with {8,10} at the end since the lookahead pattern is non-consuming):
^(?![0-9_])(?=.*[A-Z])(?=.*[0-9])(?=.*[$£_])[A-Za-z0-9$£_]{8,10}$
See this regex demo.
I want to find strings that contain words in a particular order, allowing non-standard characters in between the words but excluding a particular word or symbol.
I'm using javascript's replace function to find all instances and put into an array.
So, I want select...from, with anything except 'from' in between the words. Or I can separate select...from from select...from (, as long as I exclude nesting. I think the answer is the same for both, i.e. how do I write: find x and not y within the same regexp?
From the internet, I feel this should work: /\bselect\b^(?!from).*\bfrom\b/gi but this finds no matches.
This works to find all select...from: /\bselect\b[0-9a-zA-Z#\(\)\[\]\s\.\*,%_+-]*?\bfrom\b/gi but modifying it to exclude the parenthesis "(" at the end prevents any matches: /\bselect\b[0-9a-zA-Z#\(\)\[\]\s\.\*,%_+-]*?\bfrom\b\s*^\(/gi
Can anyone tell me how to exclude words and symbols within this regexp?
Many thanks
Emma
Edit: partial string input:
left outer join [stage].[db].[table14] o on p.Project_id = o.project_id
left outer join
(
select
different_id
,sum(costs) - ( sum(brushes) + sum(carpets) + sum(fabric) + sum(other) + sum(chairs)+ sum(apples) ) as overallNumber
from
(
select ace from [stage].db.[table18] J
Javascript:
sequel = stringInputAsAbove;
var tst = sequel.replace(/\bselect\b[\s\S]*?\bfrom\b/gi, function(a,b) { console.log('match: '+a); selects.push(b); return a; });
console.log(selects);
Console.log(selects) should print an array of numbers, where each number is the starting character of a select...from. This works for the second regexp I gave in my info, printing: [95, 251]. Your \s\S variation does the same, #stribizhev.
The first example ^(?!from).* should do likewise but returns [].
The third example \s*^\( should return 251 only but returns []. However I have just noticed that the positive expression \s*\( does give 95, so some progress! It's the negatives I'm getting wrong.
Your \bselect\b^(?!from).*\bfrom\b regex doesn't work as expected because:
^ means here beginning of a line, not negation of next part, so
the \bselect\b^ means, select word followed by beginning of a
line. After removal of ^ regex start to match something
(DEMO) but it is still invalid.
in multiline text .* without modification will not match new line,
so regex will match only select...from in single lines, but if you
change it for (.|\n)* (as a simple example) it will match
multiline, but still invalid
the * is greede quantifire, so it will match as much a possible,
but if you use reluctant quantifire *?, regex will match to first
occurance of from word, and int will start to return relativly
correct result.
\bselect\b(?!from) means match separate select word which is not
directly followed by separate from word, so it would be
selectfrom somehow composed of separate words (because
select\bfrom) so (?!from) doesn't work and it is redundant
In effect you will get regex very similar to what Stribizhev gave you: \bselect\b(.|\n)*?\bfrom\b
In third expression you meke same mistake: \bselect\b[0-9a-zA-Z#\(\)\[\]\s\.\*,%_+-]*?\bfrom\b\s*^\( using ^ as (I assume) a negation, not beginning of a line. Remove ^ and you will again get relativly valid result (match from select through from to closing parathesis ) ).
Your second regex works similar to \bselect\b(.|\n)*?\bfrom\b or \bselect\b[\s\S]*?\bfrom\b.
I wrote "relativly valid result", as I also think, that parsing SQL with regex could be very camplicated, so I am not sure if it will work in every case.
You can also try to use positive lookahead to match just position in text, like:
(?=\bselect\b(?:.|\n)*?\bfrom\b)
DEMO - the () was added to regex just to return beginning index of match in groups, so it would be easier to check it validity
Negation in regex
We use ^ as negation in character class, for example [^a-z] means match anything but not letter, so it will match number, symbol, whitespace, etc, but not letter from range a to z (Look here). But this negation is on a level of single character. I you use [^from] it will prevent regex from matching characters f,r,o and m (demo). Also the [^from]{4} will avoid matching from but also form, morf, etc.
To exlude the whole word from matching by regex, you need to use negative look ahead, like (?!from), which will fail to match, if there will be chosen word from fallowing given position. To avoid matching whole line containing from you could use ^(?!.*from.*).+$ (demo).
However in your case, you don't need to use this construction, because if you replace greedy quantifire .*\bfrom with .*?\bfrom it will match to first occurance of this word. Whats more it would couse problems. Take a look on this regex, it will not match anything because (?![\s\S]*from[\s\S]*) is not restricted by anything, so it will match only if there is no from after select, but we want to match also from! in effect this regex try to match and exclude from at once, and fail. so the (?!.*word.*) construction works much better to exclude matching line with given word.
So what to do if we don't what to match a word in a fragment of a match? I think select\b([^f]|f(?!rom))*?\bfrom\b is a good solution. With ([^f]|f(?!rom))*? it will match everything between select and from, but will not exclude from.
But if you would like to match only select...from not followed by ( then it is good idea to use (?!\() like. But in your regex (multiline, use of (.|\n)*? or [\s\S]*? it will cause to match up to next select...from part, because reluctant quantifire will chenge a plece where it need to match to make whole regex . In my opinion, good solution would be to use again:
select\b([^f]|f(?!rom))*?\bfrom\b(?!\s*?\()
which will not overlap additional select..from and will not match if there is \( after select...from - check it here