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.
from mrjob.job import MRJob
import re
Creation_date=re.compile('CreationDate=\"[0-9]*\"[:17]')
class Part2(MRJob):
def mapper(self, _, line):
DateOnly=Creation_date.group(0).split("=")
if(DateOnly > 2013):
yield None, 1
def reducer(self, key, values):
yield key, sum(values)
if __name__ == '__main__':
Part1.run()
I have written python code for MapReduce Job where CreationDate="2010-07-28T19:04:21.300". I have to find all the dates where creation date is at or after 2014-01-01. But I have encountered an error.
Creation_date is just a regex.
You need to match your input string before you can call group(0)
Regular expression object (the result of re.compile) does not have group method:
>>> pattern = re.compile('CreationDate="([0-9]+)"')
>>> pattern.group
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: '_sre.SRE_Pattern' object has no attribute 'group'
To get a match object (which has a group method), you need to match the pattern against the string (line) using regex.search method (or regex.match method depending on your need):
>>> pattern.search('CreationDate="2013"')
<_sre.SRE_Match object at 0x7fac5c64e8a0>
>>> pattern.search('CreationDate="2013"').group(1) # returns a string
'2013'
Creation_date = re.compile('CreationDate="([0-9]+)"')
def mapper(self, _, line):
date_only = Creation_date.search(line), group(1)
if int(date_only) > 2013:
yield None, 1
NOTE: modifed the regular express to capture the numeric part as a group. and convert the matched string to int (comparing string with the number 2013 has no meaning, or raise exception depending on Python version)
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.
I have a string that looks like a path from which I am trying to extract 020414_001 with a regular expression I got from here.
str1 = "Test 123 <C:\User\Test\xyz\022014-101\more\stuff\022014\1> Text"
Actually I am retrieving the string from a text file so I dont have to escape it, but for testing purpose I used this string instead:
str1 = <C:\\User\\Test\\xyz\\022014-101\\more\\stuff\\022014\\1>
Here is the code I tried to match the first occuring 022014-101:
import re
p = re.compile('(?<=\\)[\d]{6}[^\\]*')
m = p.match(str1)
print m.group(0) #Line 6
It gave me this error:
Traceback (most recent call last):
File "test12.py", line 6, in <module>
print m.group(0)
AttributeError: 'NoneType' object has no attribute 'group'
How can I get the desired output 020414_001 ?
EDIT:
That did it:
import re
m = re.search(r'(?<=\\)[\d]{6}[^\\]*', str1)
print m.group(0)
I have data split into fileids. I am trying to go through the data per fileid and search for emoticons :( and :) as defined by the regex. If an emoticon is found I need to retain the information a) the emoticon was found b) in this fileid. When I run this piece of script and print the emoticon dictionary I get 0 as a value. How is this possible? I am a beginner.
emoticon = 0
for fileid in corpus.fileids():
m = re.search('^(:\(|:\))+$', fileid)
if m is not None:
emoticon +=1
It looks to me like your regex is working, and that m should indeed not be None.
>>> re.search('^(:\(|:\))+$', ':)').group()
':)'
>>> re.search('^(:\(|:\))+$', ':)').group()
':)'
>>> re.search('^(:\(|:\))+$', ':):(').group()
':):('
>>> re.search('^(:\(|:\))+$', ':)?:(').group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
However, a few things are questionable to me.
this will only match strings that are 100% emoticons
is fileid really what you're searching?