Regular Expression to extract multiple parts when some string parts are absent - regex

I am trying to create a regular expression that will capture several sections of a string. This is the expression I have created:
([0-9]{6}[-*][0-9xX]{7}).*([0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}).*([FPTSUCD])=?([01][*-])
The string that this runs against can appear in two different styles:
# 141803-6310114 #3-0-2 T0-jL
Or
]#0-7-4 C1-vU
When I use the first string I get all the parts I need.
141803-6310114
3-0-2
T
0-
When I use the second string I get no matches. This second sting is basically the same as the first but without this part “141803-6310114”. I would like the expression to work with both strings but for the number sequence to be optional. Can anyone advise on what the expression should look like to do this?

This will get you the parts in both cases:
(?:(\d{6}[-*][\dxX]{7}))?[^\d]*(\d{1,3}-\d{1,3}-\d{1,3}) ([FPTSUCD])=?([01][*-])
Made the first group optional (?) and changed the "eat all" between the first two groups to a "eat all non digits" + other clean up to make it more readable (at least to me ;)).
Regards

Related

Regular Expression misses matches in string

I'm trying to write a regular expression that captures desired strings between strings
("f38 ","f38 ","f1 ", "..") and ("\par","\hich","{","}","","..") from a decompiled DOC file and append each match to an array to eventually be printed out into a new file.
I'm having an issue with catching certain strings between "f38 " and "\hich" (usually when the string spans multiple lines but there is at least 1 exception to this I've found in the example string snippet of the DOC file I'm using on regex101.com)
Here is the regular expression as I have it now
(?<=f38 |f38 | |f1 |\.\.)\w.+(?=\\par|\\cell |\\hich|{|}|\\|\.\.)
The troublesome matches come out including "\hich". Like "e\hich" and "d\hich" and I want to match "e" and "d" respectively in these examples not the \hich portion. I'm thinking the problem is with handling the newline/line-breaks somehow.
Here is a smaller snippet of the input string, I have bolded what is matched and bolded + capitalized the problematic match. From this I want the "e" not the \hich. Note that above there are 2 examples of things going right and "\hich" is not included in the match.
l\hich\af38\dbch\af31505\loch\f38 ..ikely to involve asbestos exposure: removal, encapsulation, alteration, repair, maintenance, insulation, spill/emergency clean-up, transportation, disposal and storage of ACM. The general industry standards cover all other operations where exposure to asb..\hich\af38\dbch\af31505\loch\f38 E\HICH\af38\dbch\af31505\loch\f38 stos is possible
Here is an example with a longer portion of the input string at regex101.com
Any help would be appreciated. Thanks!
The problem is with the part you want to match those single-character samples. \w.+ requires at least two characters to match. So, for when you get "e\hich" that first backslash get matched to the dot in regex and lasts until the next backslash (which is one of the "terminators" listed in the positive lookahead portion of the regex).
You might want to use * instead of +.

Regex: matching between underscores

For example, I have a string 111352_01_2_SAMPLE_TEXT_SAMPLE. I need to match first, second, third number and remaining text.
Currently I have this:
First number: ^[^_]+(?=_) (Everything until 1. underscore)
Second number: (?<=_)[^_]*(?=_) (Everything between 1. and 2. underscore)
Remaining text: (?:.*?_){3}(.*)\s* (Text after third occurrence of underscore)
Is there any more "readable" way of building expression, since the logic for first three matches in quite similar.
And what's the best way of writing expression for matching everything
Since you tagged regex-group I think a more straightforward way of retrieving these three substring could be:
^(.*?)_(.*?)_.*?_(.*)$
See the demo
Maybe you are looking to get a single regex expressions that is applicable to whichever element from the string you want. In that case you could use:
^(?:.*?_){0}([^\n_]+)
This is a zero-index type of retrieving elements delimited by an underscore. However, I do not see the benefit over a regular split() function. Change the zero to a 1, 2 or 3 etc.
Just use
^(\d+)_(\d+)_(\d+)_(.+)
See a demo on regex101.com.

Regular expression to check strings containing a set of words separated by a delimiter

As the title says, I'm trying to build up a regular expression that can recognize strings with this format:
word!!cat!!DOG!! ... Phone!!home!!
where !! is used as a delimiter. Each word must have a length between 1 and 5 characters. Empty words are not allowed, i.e. no strings like !!,!!!! etc.
A word can only contain alphabetical characters between a and z (case insensitive). After each word I expect to find the special delimiter !!.
I came up with the solution below but since I need to add other controls (e.g. words can contain spaces) I would like to know if I'm on the right way.
(([a-zA-Z]{1,5})([!]{2}))+
Also note that empty strings are not allowed, hence the use of +
Help and advices are very welcome since I just started learning how to build regular expressions. I run some tests using http://regexr.com/ and it seems to be okay but I want to be sure. Thank you!
Examples that shouldn't match:
a!!b!!aaaaaa!!
a123!!b!!c!!
aAaa!!bbb
aAaa!!bbb!
Splitting the string and using the values between the !!
It depends on what you want to do with the regular expression. If you want to match the values between the !!, here are two ways:
Matching with groups
([^!]+)!!
[^!]+ requires at least 1 character other than !
!! instead of [!]{2} because it is the same but much more readable
Matching with lookahead
If you only want to match the actual word (and not the two !), you can do this by using a positive lookahead:
[^!]+(?=!!)
(?=) is a positive lookahead. It requires everything inside, i.e. here !!, to be directly after the previous match. It however won't be in the resulting match.
Here is a live example.
Validating the string
If you however want to check the validity of the whole string, then you need something like this:
^([^!]+!!)+$
^ start of the string
$ end of the string
It requires the whole string to contain only ([^!]+!!) one or more than one times.
If [^!] does not fit your requirements, you can of course replace it with [a-zA-Z] or similar.

Trying to extract repeating pattern from string in php/javascript

The following is in PHP but the regex will also be used in javascript.
Trying to extract repeating patterns from a string
string can be any of the following:
"something arbitrary"
"D123"
"D111|something"
"D197|what.org|when.net"
"D297|who.197d234.whatever|when.net|some other arbitrary string"
I'm currently using the following regex: /^D([0-9]{3})(?:\|([^\|]+))*/
This correctly does not match the first string, matches the second and third correctly. The problem is the third and fourth only match the Dxxx and the last string. I need each of the strings between the '|' to be matched.
I'm hoping to use a regex as it makes it a single step. I realize I could just detect the leading Dxxx then use explode or split as appropriate to break the strings out. I've just gotten stuck on wanting a single regular expression match step.
This same regex may be used in Python as well so just want a generic regex solution.
There is no way to have a dynamic number of capture groups in a regular expression, but if you know some upper limit to how many parts you would have in one string, you can just repeat the pattern that many times:
/^D([0-9]{3})(?:$|\|)(.*?)(?:$|\|)(.*?)(?:$|\|)(.*?)(?:$|\|)(.*?)(?:$|\|)/
So after the initial ^D([0-9]{3})(?:$|\|) you just repeat (.*?)(?:$|\|) as many times as you need it.
When the string has fewer elements, those remaining capture groups will match the empty string.
See regex tester.
Is something like preg_match_all() (the PHP variant of a global match) also acceptable for you?
Then you could use:
^(?|D([0-9]{3})|^.+$|(?!^)\|([^|\n]*)(?=\||$))
This will match everything in a string in different matches, e.g. take your string:
D197|what.org|when.net
It will you then give three matches:
D197
what.org
when.net
Running live: https://regex101.com/r/jL2oX6/4 (Everything in green are your group matches. Ignore what's in blue.)

Combine Regexp?

After collecting user input for various conditions like
Starts with : /(^#)/
Ends with : /(#$)/
Contains : /#/
Doesn't contains
To make single regex if user enter multiple conditions,
I combine them with "|" so if 1 and 2 given it become /(^#)|(#$)/
This method works so far but,
I'm not able to determine correctly, What should be the regex for the 4th condition? And combining regex this way work?
Update: #(user input) won't be same
for two conditions and not all four
conditions always present but they can
be and in future I might need more
conditions like "is exactly" and "is
exactly not" etc. so, I'm more curious
to know this approach will scale ?
Also there may be issues of user input
cleanup so regex escaped properly, but
that is ignored right now.
Will the conditions be ORed or ANDed together?
Starts with: abc
Ends with: xyz
Contains: 123
Doesn't contain: 456
The OR version is fairly simple; as you said, it's mostly a matter of inserting pipes between individual conditions. The regex simply stops looking for a match as soon as one of the alternatives matches.
/^abc|xyz$|123|^(?:(?!456).)*$/
That fourth alternative may look bizarre, but that's how you express "doesn't contain" in a regex. By the way, the order of the alternatives doesn't matter; this is effectively the same regex:
/xyz$|^(?:(?!456).)*$|123|^abc/
The AND version is more complicated. After each individual regex matches, the match position has to be reset to zero so the next regex has access to the whole input. That means all of the conditions have to be expressed as lookaheads (technically, one of them doesn't have to be a lookahead, I think it expresses the intent more clearly this way). A final .*$ consummates the match.
/^(?=^abc)(?=.*xyz$)(?=.*123)(?=^(?:(?!456).)*$).*$/
And then there's the possibility of combined AND and OR conditions--that's where the real fun starts. :D
Doesn't contain #: /(^[^#]*$)/
Combining works if the intended result of combination is that any of them matching results in the whole regexp matching.
If a string must not contain #, every character must be another character than #:
/^[^#]*$/
This will match any string of any length that does not contain #.
Another possible solution would be to invert the boolean result of /#/.
In my experience with regex you really need to focus on what EXACTLY you are trying to match, rather than what NOT to match.
for example
\d{2}
[1-9][0-9]
The first expression will match any 2 digits....and the second will match 1 digit from 1 to 9 and 1 digit - any digit. So if you type 07 the first expression will validate it, but the second one will not.
See this for advanced reference:
http://www.regular-expressions.info/refadv.html
EDITED:
^((?!my string).)*$ Is the regular expression for does not contain "my string".
1 + 2 + 4 conditions: starts|ends, but not in the middle
/^#[^#]*#?$|^#?[^#]*#$/
is almost the same that:
/^#?[^#]*#?$/
but this one matches any string without #, sample 'my name is hal9000'
Combining the regex for the fourth option with any of the others doesn't work within one regex. 4 + 1 would mean either the string starts with # or doesn't contain # at all. You're going to need two separate comparisons to do that.