I am trying to put together a regex expression that matches a word (only one per line) that starts and ends with the same three characters.
I was able to write a solution for words that are at least 6 characters long (meaning there is no overlap), but I am unsure how to do it for overlapping starts and ends such as "heheh".
This is what I have, nice and simple:
^(...).*\1$
I am inclined to believe that this might have something with lookahead and lookbehind but I am not sure.
Any help would be appreciated, thank you!
You will need lookarounds since they are non-consuming patterns, i.e. the regex index is not advanced when the lookaround pattern is matched.
For example, you may do this with GNU grep:
grep -P '^(?=(...)).+\1$' file
grep -P '^(?=(\S{3})).+\1$' file # To avoid counting in spaces
grep -P '^(?=(\w{3})).+\1$' file # Or only allowing letters/digits/underscores
grep -P '^(?=(\p{L}{3})).+\1$' file # Or only allowing letters
See the regex demo
Details
^ - start of string
(?=(...)) - a positive lookahead with a capturing group inside that matches any 3 chars
.+ - any 1+ chars other than line break chars as many as possible
\1 - Group 1 value
$ - the end of string.
To extract words, you may use \w shorthand (that matches letters, digits and underscores) and word boundaries \b:
grep -oP '\b(?=(\w{3}))\w+\1\b' file
See another demo.
Details
\b - a word boundary (start of word here, because it is followed with word chars)
(?=(\w{3})) - a positive lookahead making sure there are 3 word chars while capturing them into Group 1
\w+ - 1+ word chars (not 0 or more because otherwise a 3-char word would be matched)
\1 - Group 1 value
\b - end of word here (as it is preceded with word chars).
Related
I've been trying to solve this problems for few hours but with no luck. The task is to write a regular expression that matches at least four words starting with the same letter. But! These words do not have to be one after another.
This regex should be able to match a line like this:
cat color coral chat
but also one like this:
cat take boom candle creepy drum cheek
Thank you!
So far I have got this regex but it only matches words when they are in order.
(\w)\w+\s+\1\w+\s+\1\w+\s+\1
If you have only words in the line that can be matched with \w:
\b(\w)\w*(?:(?:\s+\w+)*?\s+\1\w*){3}
Explanation
\b A word boundary to prevent a partial word match
(\w)\w* Capture a single word character in group 1 followed by matching optional word characters
(?: Non capture group to repeat as a whole part
(?:\s+\w+)*? Match 1+ whitespace chars and 1+ word chars in between in case the word does not start with the character captured in the back reference
\s+\1\w* Match 1+ whitespace chars, a backreference to the same captured character and optional word characters
){3} Close the non capture group and repeat 3 times
See a regex demo
Note that \s can also match a newline.
If the words that should with the same character should be at least 2 characters long (as (\w)\w+ matches 2 or more characters)
\b(\w)\w+(?:(?:\s+\w+)*?\s+\1\w+){3}
See another regex demo.
Another idea to match lines with at least 4 words starting with the same letter:
\b(\w)(?:.*?\b\1){3}
See this demo at regex101
This is not very accurate, it just checks if there are three \b word boundaries, each followed by \1 in the first group \b(\w) captured character to the right with .*? any characters in between.
I'm trying to find a solution to a regex that can match anything after a string or nothing, but if there's something it can't be a dot .
is it possible to do without negative lookahead?
here's an example regex:
.*\.(cpl)[^.].*
now the string:
C:\Windows\SysWOW64\control.exe mlcfg32.cpl sounds
this one is matched, but if there's only:
C:\Windows\SysWOW64\control.exe mlcfg32.cpl
it's not matched because due to the dot blacklist it's searching for any character after cpl,if i use ? after the [^.] however it won't blacklist the . in case there's something else after, so it will capture this even if it shouldn't:
C:\Windows\SysWOW64\control.exe mlcfg32.cpl. sounds
can it be done without using negative lookaheads? - ?!
You may use this regex:
.*\.cpl(?:[^.].*|$)
RegEx Demo
RegEx Breakdown:
.*: Match 0 or more of any character
\.cpl: Match .cpl
(?:[^.].*|$): Match end of string or a non-dot followed by any text
You can use
.*\.(cpl)(?:[^.].*)?$
See the regex demo. Details:
.* - zero or more chars other than line break chars as many as possible
\. - a dot
(cpl) - Group 1: cpl
(?:[^.].*)? - an optional non-capturing group that matches a char other than . char and then zero or more chars other than line break chars as many as possible
$ - end of string.
I want to write regex for the following statement and match the bolded characters "The following strings must be matched
xyz.90001DUS.annotations and xyz.765896DUS.courses".
I tried to write one using regex but it is not matching above strings, can someone please help me?
It should match whole of bolded strings, this is the only criteria.
^xyz.([0-9])?DUS.annotations(.*)?\.annotations$
Your ^xyz.([0-9])?DUS.annotations(.*)?\.annotations$ cannot match the strings inside a longer string due to anchors, ^ and $. Besides, . matches any char other than line break chars, ([0-9])? matches a single optional digit (while you have five in 90001). The (.*)?\.annotations part would match any zero or more chars other than line break chars as many as possible consuming chars up to the last occurrence of .annotations.
What you can use is
xyz\.\d+DUS\.\w+
Or, with word boundaries:
\bxyz\.\d+DUS\.\w+ <<< In most NFA regex flavors
\yxyz\.\d+DUS\.\w+ <<< In PostgreSQL, Tcl
\mxyz\.\d+DUS\.\w+ <<< R (TRE), Tcl
\<xyz\.\d+DUS\.\w+ <<< GNU word boundary
[[:<:]]xyz\.\d+DUS\.\w+ <<< POSIX word boundary
See the regex demo. You do not need a word boundary after \w+, there is always a word boundary after the trailing \w+ in any regex pattern.
Details:
xyz\. - xyz.
\d+ - one or more digits
DUS\. - DUS.
\w+ - one or more word chars.
I have this kind of text:
other text opt1 opt2 opt3 I_want_only_this_text because_of_this
And am using this regex:
(?<=opt1|opt2|opt3).*?(?=because_of_this)
Which returns me:
opt2 opt3 I_want_only_this_text
However, I want to match only "I_want_only_this_text".
What is the best way to achieve this?
I don't know in what order the opt's will appear and they are only examples. Actual words will be different and there will be more of them.
Test screenshot
Actual data:
regex
(?<=※|を|備考|町|品は|。).*(?=のお届けとなります|でお届けします|にてお届け致します|にてお届けいたします)
text
こだわり豚には通常の豚よりビタミンB1が2倍以上あります。私たちの育てた愛情たっぷりのこだわり豚をぜひ召し上がってください。商品説明名称えびの産こだわり豚切落し産地宮崎県えびの市内容量500g×8パック合計4kg賞味期限90日保存方法-15℃以下で保存すること提供者株式会社さつま屋産業備考・本お礼品は冷凍でのお届けとなります
what I want to get:
冷凍で
You can use
(?<=※|を|備考|町|品は|。)(?:(?!※|を|備考|町|品は|。).)*?(?=のお届けとなります|でお届けします|にてお届け致します|にてお届けいたします)
See the regex demo. The scheme is the same as in (?<=opt1|opt2|opt3)(?:(?!opt1|opt2|opt3).)*?(?=because_of_this) (see demo).
The tempered greedy token solution allows you to match multiple occurrences of the same pattern in a longer string.
Details
(?<=※|を|備考|町|品は|。) - a positive lookbehind that matches a location that is immediately preceded with one of the alternatives listed in the lookbehind
(?:(?!※|を|備考|町|品は|。).)*? - any char other than a line break char, zero or more but as few as possible occurrences, that is not a starting point of any of the alternative patterns in the negative lookahead
(?=のお届けとなります|でお届けします|にてお届け致します|にてお届けいたします) - a positive lookahead that requires one of the alternative patterns to appear immediately to the right of the current location.
You could add a negative lookahead (?!\s*opt\d) to assert that there is no opt and a digit to the right. You can use a character class to list the digits 1, 2 and 3 instead of using the alternation with |.
(?<=\bopt[123]\s(?!\s*opt\d)).*?(?=\s*\bbecause_of_this\b)
Regex demo
It might be a bit more efficient to use a match with a capture group:
\bopt[123]\s(?!\s*opt\d)(.*?)\s*\bbecause_of_this\b
Regex demo
What about:
.*\bopt[123]\b\s*(.*?)\s*because_of_this\b
See the online demo.
.* - A greedy match of any character other than newline upto the last occurence of:
\bopt[123]\b - A word boundary followed by literally "opt" with a trailing number 1, 2 or 3 and another word boundary.
\s* - 0+ whitespace characters.
(.*?) - A 1st capture group with a lazy match of 0+ characters upto:
\s* - 0+ whitespace characters.
because_of_this\b - Literally "because_of_this" followed by a word-boundary.
If you need to have this written out in alternations:
.*\b(?:opt1|opt2|opt3)\b\s*(.*?)\s*because_of_this\b
See that demo.
I'm trying a regex fro Alpha Numeric of length 7 (with positions 1,3,4 as characters and positions 2,5,6,7 as digits).
[a-zA-Z]|[0-9]|[a-zA-Z]|[a-zA-Z]|[0-9]|[0-9]|[0-9]
Can someone help me?
The sequence "character, digit, character, character, digit, digit, digit" is expressed in regex as
[a-zA-Z][0-9][a-zA-Z]{2}[0-9]{3}
If you're working in PCRE (with say, PHP):
^([a-zA-Z])([0-9])(?1){2}(?2){3}$
Breakdown:
^ - from the start of the string
([a-zA-Z]) - match and capture a single character in the ranges given: a-z, A-Z
([0-9]) - match and capture a single character in the ranges given: 0-9
(?1){2} - redo the regex in the first group twice (recursive subpattern)
(?2){3} - redo the regex in the second group 3 times (recursive subpattern)
$ - the end of the string
If you want to match this in the middle of a sentence, exchange ^ and $ for \b - which will match a word boundary
See the demo
If you're not using PCRE:
^[a-zA-Z][0-9][a-zA-Z]{2}[0-9]{3}$
Which does the same thing, but has some copy-paste involved