Get the part of the string matched by regex - python

In the case of re.search(), is there a way I can get hold of just the part of input string that matches the regex? i.e. I just want the "heeehe" part and not the stuff that comes before it:
>>> s = "i got away with it, heeehe"
>>> import re
>>> match = re.search("he*he", s)
>>> match.string
'i got away with it, heeehe'
>>> match.?
'heeehe'

match.group(0) is the matched string.
Demo:
>>> import re
>>> s = "i got away with it, heeehe"
>>> match = re.search("he*he", s)
>>> match.group(0)
'heeehe'
You can also omit the argument, 0 is the default.

Related

python3 regex returns empty tuple

I'm trying to apply regex to gather data from a file, and I only get empty results. For example, this little test (python3.4.3)
import re
a = 'abcde'
r = re.search('a',a)
print(r.groups())
exit()
Results with empty tuple (()). Clearly, I'm doing something wrong here, but what?
Comment:
What I'm actually trying to do is to interpret expressions such as 0.7*sqrt(2), by finding the value inside the parenthesis.
It happens because there are no groups in your regex. If you replace it with:
>>> r = re.search('(a)',a)
you'll get the groups:
>>> print(r.groups())
('a',)
Using group should work with the first option:
>>> print(re.search('a',a).group())
a
r.groups() returns an empty tuple, because your regular expression did not contain any group.
>>> import re
>>> a = 'abcde'
>>> re.search('a', a)
<_sre.SRE_Match object; span=(0, 1), match='a'>
>>> re.search('a', a).groups()
()
>>> re.search('(a)', a).groups()
('a',)
Have a look at the re module documentation:
(...)
Matches whatever regular expression is inside the parentheses, and indicates the start and end of a group;
Edit: If you want to catch the bit between the brackets in the expression O.7*sqrt(2), you could use the following pattern:
>>> re.search('[\d\.]+\*sqrt\((\d)\)', '0.7*sqrt(2)').group(1)
'2'

Combining two patterns with named capturing group in Python?

I have a regular expression which uses the before pattern like so:
>>> RE_SID = re.compile(r'(?P<sid>(?<=sid:)([A-Za-z0-9]+))')
>>> x = RE_SID.search('sid:I118uailfriedx151201005423521">>')
>>> x.group('sid')
'I118uailfriedx151201005423521'
and another like so:
>>> RE_SID = re.compile(r'(?P<sid>(?<=sid:<<")([A-Za-z0-9]+))')
>>> x = RE_SID.search('sid:<<"I118uailfriedx151201005423521')
>>> x.group('sid')
'I118uailfriedx151201005423521'
How can I combine these two patterns in a way that, after parsing these two different lines,:
sid:A111uancalual2626x151130185758596
sid:<<"I118uailfriedx151201005423521">>
returns only the corresponding id to me.
RE_SID = re.compile(r'sid:(<<")?(?P<sid>([A-Za-z0-9]+))')
Use this, I've just tested and it is working for me. I've moved some part out.
Instead of tweaking your regex, you can make your strings easier to parse by just removing any characters except alphanumeric and a colon. Then, just split by colon and get the last item:
>>> import re
>>>
>>> test_strings = ['sid:I118uailfriedx151201005423521">>', 'sid:<<"I118uailfriedx151201005423521']
>>> pattern = re.compile(r"[^A-Za-z0-9:]")
>>> for test_string in test_strings:
... print(pattern.sub("", test_string).split(":")[-1])
...
I118uailfriedx151201005423521
I118uailfriedx151201005423521
You can achieve what you want with a single regex:
\bsid:\W*(?P<sid>\w+)
See the regex demo
The regex breakdown:
\bsid - whole word sid
: - a literal colon
\W* - zero or more non-word characters
(?P<sid>\w+) - one or more word characters captured into a group named "sid"
Python demo:
import re
p = re.compile(r'\bsid:\W*(?P<sid>\w+)')
#test_str = "sid:I118uailfriedx151201005423521\">>" # => I118uailfriedx151201005423521
test_str = "sid:<<\"I118uailfriedx151201005423521" # => I118uailfriedx151201005423521
m = p.search(test_str)
if m:
print(m.group("sid"))

Do not match if word appears in regex

I have a url, and I want it to NOT match if the word 'season' is contained in the url. Here are two examples:
CONTAINS SEASON, DO NOT MATCH
'http://imdb.com/title/tt0285331/episodes?this=1&season=7&ref_=tt_eps_sn_7'
DOES NOT CONTAIN SEASON, MATCH
'http://imdb.com/title/tt0285331/
Here is what I have so far, but I'm afraid the .+ will match everything until the end. What would be the correct regex to use here?
r'http://imdb.com/title/tt(\d)+/.+^[season].+'
Use a negative lookahead:
urls='''\
http://imdb.com/title/tt0285331/episodes?this=1&season=7&ref_=tt_eps_sn_7
http://imdb.com/title/tt0285331/'''
import re
print re.findall(r'^(?!.*\bseason\b)(.*)', urls, re.M)
# ['http://imdb.com/title/tt0285331/']
You cannot use whole words inside of character classes, you have to use a Negative Lookahead.
>>> s = '''
http://imdb.com/title/tt0285331/episodes?this=1&season=7&ref_=tt_eps_sn_7
http://imdb.com/title/tt0285331/
http://imdb.com/title/tt1111111/episodes?this=2
http://imdb.com/title/tt0123456/episodes?this=1&season=1&ref_=tt_eps_sn_1'''
>>> import re
>>> re.findall(r'\bhttp://imdb.com/title/tt(?!\S+\bseason)\S+', s)
# ['http://imdb.com/title/tt0285331/', 'http://imdb.com/title/tt0285331/episodes?this=2']
Use a negative lokahead just after to tt\d+/,
>>> import re
>>> s = """http://imdb.com/title/tt0285331/episodes?this=1&season=7&ref_=tt_eps_sn_7
... http://imdb.com/title/tt0285331/
... """
>>> m = re.findall(r'^http://imdb.com/title/tt\d+/(?:(?!season).)*$', s, re.M)
>>> for i in m:
... print i
...
http://imdb.com/title/tt0285331/

python 3 regular expression match string meta-character

I want to write a line of regular expression that can match strings like "(2000)" with years in parentheses. then I can check if any string contains the substring "2000".
for example, I want the regex to match (2000) not 2000, or (20000),or (200).
That is to say: they have to have exactly four digits, the first digit between 1 and 2; they have to include the parentheses.
also 2000 is just an example I use but really I want to the regex to include all the possible years.
You have to escape the open and close paranthesis,
>>> import re
>>> str = """foo(2000)bar(1000)foobar2000"""
>>> regex = r'\(2000\)'
>>> result = re.findall(regex, str)
>>> print(result)
['(2000)']
OR
>>> import re
>>> str = """foo(2000)bar(1000)foobar(2014)barfoo(2020)"""
>>> regex = r'\([0-9]{4}\)'
>>> result = re.findall(regex, str)
>>> print(result)
['(2000)', '(1000)', '(2014)', '(2020)']
It matches all the four digit numbers(year's) present within the paranthesis.
Special characters need to be escaped with a backslash. A parenthesis ( becomes \(. Therefore (2000) becomes \(2000\).
Then you can do something like:
if re.search(r"\(2000\)", subject):
# Successful match
else:
# Match attempt failed
>>> import re
>>> x = re.match(r'\((\d*?)\)', "(2000)")
>>> x.group(1)
'2000'

How to substitute chars using unicode regex range

I am trying to remove chars from an unicode string. I have a whitelist of allowed unicode chars and I would like to remove everything that is not on the list.
allowed_list = ur'[\u0041-\u005A]|[\u0061-\u007A]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u012F]|\u0131|[\u0386]|[\u0388-\u038A]'
negated_list = ur'[^\u0041-\u005A]|[^\u0061-\u007A]|[^\u00C0-\u00D6]|[^\u00D8-\u00F6]|[^\u00F8-\u012F]|^\u0131|[^\u0386]|[^\u0388-\u038A]'
I am testing it with a subset of my list and I don't get why it is not working.
This removes all but lowercase latin chars:
>>> mystr = 'Arugg^]T'
>>> myre = re.compile(ur'[^\u0061-\u007A]', re.UNICODE)
>>> result = myre.sub('', mystr)
>>> result
'rugg'
This removes all but uppercase latin chars:
>>> mystr = 'Arugg^]T'
>>> myre = re.compile(ur'[^\u0041-\u005A]', re.UNICODE)
>>> result = myre.sub('', mystr)
>>> result
'AT'
But when I combine them, all chars get removed:
>>> mystr = 'Arugg^]T'
>>> myre = re.compile(ur'[^\u0041-\u005A]|[^\u0061-\u007A]', re.UNICODE)
>>> result = myre.sub('', mystr)
>>> result
''
When I tested the regex [^\u0041-\u005A]|[^\u0061-\u007A] on https://pythex.org/ it does what I am expecting, but when I atempt to use it in my code, it is not doing what I want it to. What am I missing?
Thank you in advance!
Your regex is not correct, you are using | which checks if either one is true.
You need to create one expression with multiple ranges,
[^\u0041-\u005A\u0061-\u007A] will match any characters except range \u0041-\u005A or \u0061-\u007A.
import re
regex = r"[^\u0041-\u005A\u0061-\u007A]"
test_str = "Arugg^]T"
myre = re.compile(regex, re.UNICODE)
result = myre.sub('', test_str)
print(result)
# output,
AruggT
Implicitly positive, regex class items are OR'd together.
Your regex is then the same as
[\u0041-\u005a\u0061-\u007a\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u012f\u0131\u0386\u0388-\u038a]
But for the Negative regex class [^], items are individually negated then AND'ed together.
That regex is then
[^\u0041-\u005a\u0061-\u007a\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u012f\u0131\u0386\u0388-\u038a]
which is logically the same as
[^\u0041-\u005A] and [^\u0061-\u007A] and [^\u00C0-\u00D6] and [^\u00D8-\u00F6] and [^\u00F8-\u012F] and [^\u0131] and [^\u0386] and [^\u0388-\u038A]
What you tried to do was negate each item, then OR them together
which is not the same.
You are replacing all characters that are
not in '[^\u0041-\u005A]' or not in [^\u0061-\u007A]' (due to the ^) .
If either one is true, all get replaced by '' - so its always true no matter what you have.
Use ur'[^\u0041-\u005A\u0061-\u007A]' instead (both ranges inside one [...].

Categories

Resources