search substring + integer from a string in python using regular expression - python

I have a string
str="TMOUT=1800; export TMOUT"
I want to extract only TMOUT=1800 from above string, but 1800 is not constant it can be any integer value. For example TMOUT=18 or TMOUT=201 etc. I'm very new to regular expression.
I tried using code below
re.search("TMOUT=\d",str).
It is not working. Please help

\d matches a single digit. You want to match one or more digits, so you have to add a + quantifier:
re.search("TMOUT=\d+", text)
If you then you want to extract the number you have to create a group using parenthesis ():
match = re.search(r"TMOUT=(\d+)", text)
number = int(match.group(1))
Or you may want to use the named group syntax (?P<name>):
match = re.search(r"TMOUT=(?P<num>\d+)", text)
number = int(match.group("num"))
I suggest you use regex101 to test your regexes and get an explanation of what they do. Also read python's re docs to learn about the methods of the various objects and functions available.

Related

Python regex fuzzy searching

I have a question about making a pattern using fuzzy regex with the python regex module.
I have several strings such as TCATGCACGTGGGGCTGAC
The first eight characters of this string are variable (multiple options): TCAGTGTG, TCATGCAC, TGGTGGCT. In addition, there is a constant part after the variable part: GTGGGGCTGAC.
I would like to design a regex that can detect this string in a longer string, while allowing for at most 2 substitutions.
For example, this would be acceptable as two characters have been substituted:
TCATGCACGTGGGGCTGAC
TCCTGCACGTGGAGCTGAC
However, more substitutions should not be accepted.
In my code, I tried to do the following:
import regex
variable_parts = ["TCAGTGTG", "TCATGCAC", "TGGTGGCT", "GATAAGTG", "ATTAGACG", "CACTTCCG", "GTCTGTAT", "TGTCAAAG"]
string_to_test = "TCATGCACGTGGGGCTGAC"
motif = "(%s)GTGGGGCTGAC" % "|".join(variable_parts)
pattern = regex.compile(r''+motif+'{s<=2}')
print(pattern.search(string_to_test))
I get a match when I run this code and when I change the last character of string_to_test. But when I manually add a substitution in the middle of string_to_test, I do not get any match (even while I want to allow up to 2 substitutions).
Now I know that my regex is probably total crap, but I would like to know what I exactly need to do to make this work and where in the code I need to add/remove/change stuff. Any suggestions/tips are welcome!
Right now, you only add the restriction to the last C in the pattern that looks likelooks like (TCAGTGTG|TCATGCAC|TGGTGGCT|GATAAGTG|ATTAGACG|CACTTCCG|GTCTGTAT|TGTCAAAG)GTGGGGCTGAC{s<=2}.
To apply the {s<=2} quantifier to the whole expression you need to enclose the pattern within a non-capturing group:
pattern = regex.compile(fr'(?:{motif}){{s<=2}}')
The example above shows how to declare your pattern with the help of an f-string literal, where literal braces are defined with {{ and }} (doubled) braces. It yields the same result as pattern = regex.compile('(?:'+motif+'){s<=2}').
Also, note that r''+ is redundant and has no effect on the final pattern.

Get literal prefix of regex pattern

Here is the problem:
There is a list of thousands of regular expressions. I need to get regular expression which matches to the given string. Hopefully, these regexes are mutually exclusive, so if several regexes are matching at the same time, I'm ok with returning any of them.
I assume that most of regular expressions starts with literal prefix e.g.:
"some_literal_string(?:\?some_regular_part)?" → "some_literal_string"
I'd like to try the following data structure to make the search fast:
regexes = [index=prefix_length:{key=prefix:{*prefixes}]
now, to find the prefix, I need to iterate index from min(len(string), len(longest_prefix)) down to 0 and extract subset of regexes:
subset = regexes[i][string[0:i]]
Now I need to check each element for match and if pattern is found, return it, otherwise, continue with next index.
The question is: how to get literal prefix of a regular expression in the common case?
I came to the following regular expression:
(?:[^.^$*+?{\\[|(]|(?:\\(?:[^\dAbBdDsSwWZ]|0|[0-7]{3})))*(?![*?|]|{\d+(?:,\d*)?})
It's needed to replace backslash+symbol with the symbol in matched string after search:
\$ → $
It's needed to replace octal escapes:
\0100 → #
https://regex101.com/r/fF8aB9/2

Python Regex for alpha(alpha|digit)*

I'm trying to produce a python regex to represent identifiers for a lexical analyzer. My approach is:
([a-zA-Z]([a-zA-Z]|\d)*)
When I use this in:
regex = re.compile("\s*([a-zA-Z]([a-zA-Z]|\d)*)")
regex.findall(line)
It doesn't produce a list of identifiers like it should. Have I built the expression incorrectly?
What's a good way to represent the form:
alpha(alpha|digit)*
With the python re module?
like this:
regex = re.compile(r'[a-zA-Z][a-zA-Z\d]*')
Note the r before the quote to obtain a raw string, otherwise you need to escape all backslashes.
Since the \s* before is optional, you can remove it, like capture groups.
If you want to ensure that the match isn't preceded by a digit, you can write it like this with a negative lookbehind (?<!...):
regex = re.compile(r'(?:^|(?<![\da-zA-Z]))[a-zA-Z][a-zA-Z\d]*')
Note that with re.compile you can use the case insensitive option:
regex = re.compile(r'(?:^|(?<![\da-z]))[a-z][a-z\d]*', re.I)

Python regex returns a part of the match when used with re.findall

I have been trying to teach myself Python and am currently on regular expressions. The instructional text I have been using seems to be aimed at teaching Perl or some other language that is not Python, so I have had to adapt the expressions a bit to fit Python. I'm not very experienced, however, and I've hit a snag trying to get an expression to work.
The problem involves searching a text for instances of prices, expressed either without decimals, $500, or with decimals, $500.10.
This is what the text recommends:
\$[0-9]+(\.[0-9][0-9])?
Replicating the text, I use this code:
import re
inputstring = "$500.01"
result = re.findall( r'\$[0-9]+(\.[0-9][0-9])?', inputstring)
if result:
print(result)
else:
print("No match.")
However, the result is not $500.01, but rather:
.01
I find this strange. If I remove the parentheses and the optional decimal portion, it works fine. So, using this:
\$[0-9]+\.[0-9][0-9]
I get:
$500.01
How can I get the regular expression to return values with and without decimal portions?
Thanks.
Use a non-capturing group:
result = re.findall( r'\$[0-9]+(?:\.[0-9][0-9])?', inputstring)
^^
The re.findall function returns the list of captured texts if there are any defined in the pattern, and you have one in yours. You need to get rid of it by turning it into a non-capturing one.
re.findall(pattern, string, flags=0)
If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group.
Update
You can shorten your regex a bit by using a limiting quantifier {2} that requires exactly 2 occurrences of the preceding subpattern:
r'\$[0-9]+(?:\.[0-9]{2})?'
^^^
Or even replace [0-9] with \d:
r'\$\d+(?:\.\d{2})?'

Regular expression capturing entire match consisting of repeated groups

I've looked thrould the forums but could not find exactly how exactly to solve my problem.
Let's say I have a string like the following:
UDK .636.32/38.082.4454.2(575.3)
and I would like to match the expression with a regex, capturing the actual number (in this case the '.636.32/38.082.4454.2(575.3)').
There could be some garbage characters between the 'UDK' and the actual number, and characters like '.', '/' or '-' are valid parts of the number. Essentially the number is a sequence of digits separated by some allowed characters.
What I've came up with is the following regex:
'UDK.*(\d{1,3}[\.\,\(\)\[\]\=\'\:\"\+/\-]{0,3})+'
but it does not group the '.636.32/38.082.4454.2(575.3)'! It leaves me with nothing more than a last digit of the last group (3 in this case).
Any help would be greatly appreciated.
First, you need a non-greedy .*?.
Second, you don't need to escape some chars in [ ].
Third, you might just consider it as a sequence of digits AND some allowed characters? Why there is a \d{1,3} but a 4454?
>>> re.match(r'UDK.*?([\d.,()\[\]=\':"+/-]+)', s).group(1)
'.636.32/38.082.4454.2(575.3)'
Not so much a direct answer to your problem, but a general regexp tip: use Kodos (http://kodos.sourceforge.net/). It is simply awesome for composing/testing out regexps. You can enter some sample text, and "try out" regular expressions against it, seeing what matches, groups, etc. It even generates Python code when you're done. Good stuff.
Edit: using Kodos I came up with:
UDK.*?(?P<number>[\d/.)(]+)
as a regexp which matches the given example. Code that Kodos produces is:
import re
rawstr = r"""UDK.*?(?P<number>[\d/.)(]+)"""
matchstr = """UDK .636.32/38.082.4454.2(575.3)"""
# method 1: using a compile object
compile_obj = re.compile(rawstr)
match_obj = compile_obj.search(matchstr)
# Retrieve group(s) by name
number = match_obj.group('number')

Categories

Resources