Splitting up lines in a regular expression - python

I'm trying to break up a long regex into smaller chunks. Is it possible/good practice to change A to B?
A:
line = re.sub(r'\$\{([0-9]+)\}|\$([0-9]+)|\$\{(\w+?\=\w?+)\}|[^\\]\$(\w[^-]+)|[^\\]\$\{(\w[^-]+)\}',replace,line)
B:
line = re.sub(r'\$\{([0-9]+)\}|'
r'\$([0-9]+)|'
r'\$\{(\w+?\=\w?+)\}|'
r'[^\\]\$(\w[^-]+)|'
r'[^\\]\$\{(\w[^-]+)\}',replace,line)
Edit:
I receive the following error when running this in Python 2:
def main():
while(1):
line = raw_input("(%s)$ " % ncmd)
line = re.sub(r'''
\$\{([0-9]+)\}|
\$([0-9]+)|
\$\{(\w+?\=\w?+)\}|
[^\\]\$(\w[^-]+)|
[^\\]\$\{(\w[^-]+)\}
''',replace,line,re.VERBOSE)
print '>> ' + line
Error:
(1)$ abc
Traceback (most recent call last):
File "Test.py", line 4, in <module>
main()
File "Test.py", line 2, in main
[^\\]\$\{(\w[^-]+)\}''',replace,line,re.VERBOSE)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 151, in sub
return _compile(pattern, flags).sub(repl, string, count)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 242, in _compile
raise error, v # invalid expression
sre_constants.error: multiple repeat

You can use a triple-quoted (multi-line) string and set the re.VERBOSE flag, which allows you to break a Regex pattern over multiple lines:
line = re.sub(r'''
\$\{([0-9]+)\}|
\$([0-9]+)|
\$\{(\w+?\=\w?+)\}|
[^\\]\$(\w[^-]+)|
[^\\]\$\{(\w[^-]+)\}
''', replace, line, re.VERBOSE)
You can even include comments directly inside the string:
line = re.sub(r'''
\$\{([0-9]+)\}| # Pattern 1
\$([0-9]+)| # Pattern 2
\$\{(\w+?\=\w?+)\}| # Pattern 3
[^\\]\$(\w[^-]+)| # Pattern 4
[^\\]\$\{(\w[^-]+)\} # Pattern 5
''', replace, line, re.VERBOSE)
Lastly, it should be noted that you can likewise activate the verbose flag by using re.X or by placing (?x) at the start of your Regex pattern.

You can also separate your expression over multiple lines using double quotes, like the following:
line = re.sub(r"\$\{([0-9]+)\}|\$([0-9]+)|"
r"\$\{(.+-.+)\}|"
r"\$\{(\w+?\=\w+?)\}|"
r"\$(\w[^-]+)|\$\{(\w[^-]+)\}",replace,line)

Related

how do I get words with meta expressions from string regardless of spacing

What I want to do is getting start point of some words from string.
For example,
context = "abcd e f g ( $ 150 )"
answer = "g($150)"
I want to get the start index of answer from context which should be "9".
I tried something like this,
answer = ' ?'.join()
try:
answer = re.sub('[$]', '\$', answer)
answer = re.sub('[(]', '\(', answer)
answer = re.sub('[)]', '\)', answer)
except:
pass
start_point = re.search(answer, context).span()[0]
Because there are answers with meta expressions and answers without meta expressions I used try, except.
And I used this kinds of code,
answer = re.sub('[(]', '\(', answer)
because if I don't use it, I found that re.search(answer, context) can't find my answer from context.
then I get this error.
Traceback (most recent call last):
File "mc_answer_v2.py", line 42, in <module>
match = re.search(spaced_answer_text, mc_paragraph_text)
File "/home/hyelchung/data1/envs/albert/lib/python3.6/re.py", line 182, in search
return _compile(pattern, flags).search(string)
File "/home/hyelchung/data1/envs/albert/lib/python3.6/re.py", line 301, in _compile
p = sre_compile.compile(pattern, flags)
File "/home/hyelchung/data1/envs/albert/lib/python3.6/sre_compile.py", line 562, in compile
p = sre_parse.parse(p, flags)
File "/home/hyelchung/data1/envs/albert/lib/python3.6/sre_parse.py", line 855, in parse
p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)
File "/home/hyelchung/data1/envs/albert/lib/python3.6/sre_parse.py", line 416, in _parse_sub
not nested and not items))
File "/home/hyelchung/data1/envs/albert/lib/python3.6/sre_parse.py", line 619, in _parse
source.tell() - here + len(this))
sre_constants.error: multiple repeat at position 3
How do I fix it and is there any other good way to get the start index?
It seems possible to do it by sticking \s* (variable number of white space characters) after each escaped character of answer string.
import re
def findPosition(context, answer):
regex=r"\s*"
regAnswer=regex.join([re.escape(w) for w in answer]) + regex
# print(regAnswer)
return re.search(regAnswer, context).start()
context = "abcd e f g ( $ 150 )"
answer = "g($150)"
print(findPosition(context, answer))
Use map to escape each character
Regex replace the original string with the target string
The string find method looks for the target string. If the target string does not exist, it will not return -1 abnormally.
>>> import re
>>> context = 'abcd e f g ( $ 150 )'
>>> answer = 'g($150)'
>>> findSpacing = lambda target, src :re.sub("\s*".join(map(re.escape, target)), target, src).find(target)
>>> findSpacing(answer, context)
9
>>> findSpacing("FLAG", context)
-1
>>>

sre_constants.error: missing ),unterminated subpattern

i am gaurav and i am learning programming. i was reading regular expressions in dive into python 3,so i thought to try myself something so i wrote this code in eclipse but i got a lot of errors.can anyone pls help me
import re
def add_shtner(add):
return re.sub(r"\bROAD\b","RD",add)
print(add_shtner("100,BROAD ROAD"))
# a code to check valid roman no.
ptn=r"^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3}$)"
def romancheck(num):
num=num.upper()
if re.search(ptn,num):
return "VALID"
else:
return "INVALID"
print(romancheck("MMMLXXVIII"))
print(romancheck("MMMLxvviii"))
mul_line_str='''adding third argument
re.VERBOSE in re.search()
will ignore whitespace
and comments'''
print(re.search("re.search()will",mul_line_str,re.VERBOSE))
print(re.search("re.search() will",mul_line_str,re.VERBOSE))
print(re.search("ignore",mul_line_str,re.VERBOSE))
ptn='''
^ #beginning of the string
M{0,3} #thousands-0 to 3 M's
(CM|CD|D?C{0,3} #hundreds
(XC|XL|L?XXX) #tens
(IX|IV|V?III) #ones
$ #end of the string
'''
print(re.search(ptn,"MMMCDLXXIX",re.VERBOSE))
def romanCheck(num):
num=num.upper()
if re.search(ptn,num,re.VERBOSE):
return "VALID"
else:
return "INVALID"
print(romanCheck("mmCLXXXIV"))
print(romanCheck("MMMCCLXXXiv"))
i wrote this code and i ran it but i got this-
100,BROAD RD
VALID
INVALID
None
None
<_sre.SRE_Match object; span=(120, 126), match='ignore'>
Traceback (most recent call last):
File "G:\pydev\xyz\rts\regular_expressions.py", line 46, in <module>
print(re.search(ptn,"MMMCDLXXIX",re.VERBOSE))
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\re.py", line 182, in search
return _compile(pattern, flags).search(string)
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\re.py", line 301, in _compile
p = sre_compile.compile(pattern, flags)
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\sre_compile.py", line 562, in compile
p = sre_parse.parse(p, flags)
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\sre_parse.py", line 856, in parse
p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\sre_parse.py", line 416, in _parse_sub
not nested and not items))
File "C:\Users\Owner\AppData\Local\Programs\Python\Python36\lib\sre_parse.py", line 768, in _parse
source.tell() - start)
sre_constants.error: missing ), unterminated subpattern at position 113 (line 4, column 6)
what are these errors can anyone help me.
i have understood all the output but i am not able to understand this errors
The error means that you have passed a malformed regular expression to the search() function in line 46.
Although you have defined a valid RegEx in this line:
ptn=r"^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3}$)"
you overwrite this pattern (ptn) later with what seems to be some help/docstring:
ptn='''
^ #beginning of the string
M{0,3} #thousands-0 to 3 M's
(CM|CD|D?C{0,3} #hundreds
(XC|XL|L?XXX) #tens
(IX|IV|V?III) #ones
$ #end of the string
'''
This is not a valid RegEx pattern, it is missing a closing bracket after (CM|CD|D?C{0,3}.
You pass this new string as regular expression in the nex line print(re.search(ptn,"MMMCDLXXIX",re.VERBOSE)) and re.compile() throws that error.
If you use another name for the variable to hold your help/docstring in line 27 (based on your sample code or line 38 based on your stacktrace) everything looks fine:
100,BROAD RD
VALID
INVALID
None
None
<_sre.SRE_Match object; span=(85, 91), match='ignore'>
<_sre.SRE_Match object; span=(0, 10), match='MMMCDLXXIX'>
VALID
VALID
I have had this issue when using re.VERBOSE. I suggest not using it in that format. Create the pattern in a single line rather than over multiple lines and don't pass the verbose parameter.

How to remove all characters not inside parentheses using regex

I have a string that contains commas both inside and outside of a parentheses block:
foo(bat,foo),bat
How can I use regex to replace the comma not inside parentheses?
foo(bat,foo)bat
Do you really want to use re, or is anyway to achieve your goal is ok?
In the latter case, here is a way to do it:
mystring = 'foo(bat,foo),bat'
''.join(si + ',' if '(' in si else si for si in mystring.split(','))
#'foo(bat,foo)bat'
Assuming that there are no nested parentheses and there are no invalid pairings of parentheses, you can do this with a regex based on the fact that a comma will only be outside a pair of parentheses if and only if there are an even number of ( and ) symbols that follow it. Thus, you can use a lookahead regex to achieve this.
,(?![^(]*\))
If there are nested parentheses, it becomes a context-free grammar and you cannot capture this with a regular expression alone. You are better off just using split methods.
example:
import re
ori_str = "foo(bat,foo),bat foo(bat,foo),bat";
rep_str = re.sub(r',(?![^(]*\))', '', ori_str)
print(rep_str)
Considering that we want to remove all commas outside of all blocks and don't want to modify nested blocks.
Let's add string validation for cases when there are unclosed/unopened blocks found with
def validate_string(string):
left_parts_count = len(string.split('('))
right_parts_count = len(string.split(')'))
diff = left_parts_count - right_parts_count
if diff == 0:
return
if diff < 0:
raise ValueError('Invalid string: "{string}". '
'Number of closed '
'but not opened blocks: {diff}.'
.format(string=string,
diff=-diff))
raise ValueError('Invalid string: "{string}". '
'Number of opened '
'but not closed blocks: {diff}.'
.format(string=string,
diff=diff))
then we can do our job without regular expressions, just using str methods
def remove_commas_outside_of_parentheses(string):
# if you don't need string validation
# then remove this line and string validator
validate_string(string)
left_parts = string.split('(')
if len(left_parts) == 1:
# no opened blocks found,
# remove all commas
return string.replace(',', '')
left_outer_part = left_parts[0]
left_outer_part = left_outer_part.replace(',', '')
left_unopened_parts = left_parts[-1].split(')')
right_outer_part = left_unopened_parts[-1]
right_outer_part = right_outer_part.replace(',', '')
return '('.join([left_outer_part] +
left_parts[1:-1] +
[')'.join(left_unopened_parts[:-1]
+ [right_outer_part])])
it can look a bit nasty, i suppose, but it works.
Tests
>>>remove_commas_outside_of_parentheses('foo,bat')
foobat
>>>remove_commas_outside_of_parentheses('foo,(bat,foo),bat')
foo(bat,foo)bat
>>>remove_commas_outside_of_parentheses('bar,baz(foo,(bat,foo),bat),bar,baz')
barbaz(foo,(bat,foo),bat)barbaz
"broken" ones:
>>>remove_commas_outside_of_parentheses('(')
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in remove_commas_outside_of_parentheses
File "<input>", line 17, in validate_string
ValueError: Invalid string: "(". Number of opened but not closed blocks: 1.
>>>remove_commas_outside_of_parentheses(')')
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in remove_commas_outside_of_parentheses
File "<input>", line 12, in validate_string
ValueError: Invalid string: ")". Number of closed but not opened blocks: 1.

Using a dollar sign in enum (pypeg)?

I want to match types of the form either $f, $c, ..., $d using pypeg, so I tried putting it in an Enum as follows:
class StatementType(Keyword):
grammar = Enum( K("$f"), K("$c"),
K("$v"), K("$e"),
K("$a"), K("$p"),
K("$d"))
However, this fails:
>>> k = parse("$d", StatementType)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/pypeg2/__init__.py", line 667, in parse
t, r = parser.parse(text, thing)
File "/usr/local/lib/python3.6/site-packages/pypeg2/__init__.py", line 794, in parse
raise r
File "<string>", line 1
$d
^
SyntaxError: expecting StatementType
I have also tried replacing the $x with \$x to escape the $ character. I also tried prepending r"\$x" in hopes that it treats it as a regex object. Neither of these combinations seem to work and give the same error message. How do I get it to match the example I gave?
The default regex for Keywords is \w+. You can change it by setting the Keyword.regex class variable:
class StatementType(Keyword):
grammar = Enum( K("$f"), K("$c"),
K("$v"), K("$e"),
K("$a"), K("$p"),
K("$d"))
Keyword.regex = re.compile(r"\$\w") # e.g. $a, $2, $_
k = parse("$d", StatementType)

Trying to do a simple regex

i wan to extract (abc)(def) using the regex
which i ended up with that error below
import re
def main():
str = "-->(abc)(def)<--"
match = re.search("\-->(.*?)\<--" , str).group(1)
print match
The error is:
Traceback (most recent call last):
File "test.py", line 7, in <module>
match = re.search("\-->(.*?)\<--" , str).group()
File "/usr/lib/python2.7/re.py", line 146, in search
return _compile(pattern, flags).search(string)
TypeError: expected string or buffer
Corrected:
import re
def main():
my_string = "-->(abc)(def)<--"
match = re.search("\-->(.*?)\<--" , my_string).group(1)
print match
# (abc)(def)
main()
Note, that I renamed str to my_string (do not use standard library functions as own variables!). Maybe you can still optimize your regex with lookarounds, the lazy star (.*?) can get very ineffective sometimes.

Categories

Resources