【问题标题】:Python RegEx nested search and replacePython RegEx 嵌套搜索和替换
【发布时间】:2011-10-04 16:41:34
【问题描述】:

我需要对引号块内的所有逗号进行正则表达式搜索和替换。

"thing1,blah","thing2,blah","thing3,blah",thing4  

需要成为

"thing1\,blah","thing2\,blah","thing3\,blah",thing4  

我的代码:

inFile  = open(inFileName,'r')
inFileRl = inFile.readlines()
inFile.close()

p = re.compile(r'["]([^"]*)["]')
for line in inFileRl:
    pg = p.search(line)
    # found comment block
    if pg:
        q  = re.compile(r'[^\\],')
        # found comma within comment block
        qg = q.search(pg.group(0))
        if qg:
            # Here I want to reconstitute the line and print it with the replaced text
            #print re.sub(r'([^\\])\,',r'\1\,',pg.group(0))

我只需要根据 RegEx 过滤我想要的列,进一步过滤,
然后进行正则表达式替换,然后重新构造该行。

如何在 Python 中做到这一点?

【问题讨论】:

  • 不是一个真正的答案,但在您重新实现之前,也许 CSV 解析器可以更好地为您服务?这似乎是您正在处理的格式。
  • 我实际上希望为我的自定义 CSV 解析器准备好数据 csv.register_dialect( 'escapedExcel' , delimiter = ',' , skipinitialspace = 0 , doublequote = 1 , quoting = csv.QUOTE_ALL , quotechar = '"' , lineterminator = '\r\n' , escapechar = '\\' )
  • 我明白了,那么我相信您想使用匹配对象的spanstart 方法来获取它周围的东西并重新组合您的行。但我不确定为什么在“选择”循环之后对 sub 的单次调用是不行的。
  • @Dragos Toader:为什么要替换引号内的逗号? csv.reader 引号内的逗号没有问题。
  • 添加反斜杠只是意味着您的解析器需要处理的另一种机制。现在你也需要反斜杠所有的反斜杠。正确的解决方法是教你的 CSV 解析器忽略双引号内的逗号,或者使用现有的 CSV 解析器。

标签: python regex replace


【解决方案1】:

csv 模块非常适合解析此类数据,因为默认方言中的csv.reader 会忽略带引号的逗号。 csv.writer 由于逗号的存在而重新插入引号。我使用StringIO 为字符串提供了类似接口的文件。

import csv
import StringIO

s = '''"thing1,blah","thing2,blah","thing3,blah"
"thing4,blah","thing5,blah","thing6,blah"'''
source = StringIO.StringIO(s)
dest = StringIO.StringIO()
rdr = csv.reader(source)
wtr = csv.writer(dest)
for row in rdr:
    wtr.writerow([item.replace('\\,',',').replace(',','\\,') for item in row])
print dest.getvalue()

结果:

"thing1\,blah","thing2\,blah","thing3\,blah"
"thing4\,blah","thing5\,blah","thing6\,blah"

【讨论】:

  • +1 但是你需要写item.replace('\\,',',').replace(',','\\,') ,否则 "thing3\,blah " 被替换为 "thing3\\,blah "
【解决方案2】:

一般编辑

"thing1\\,blah","thing2\\,blah","thing3\\,blah",thing4   

在问题中,现在它不再存在了。

另外,r'[^\\],'我没有备注。

所以,我完全重写了我的答案。

"thing1,blah","thing2,blah","thing3,blah",thing4               

"thing1\,blah","thing2\,blah","thing3\,blah",thing4

正在显示字符串(我想)

import re


ss = '"thing1,blah","thing2,blah","thing3\,blah",thing4 '

regx = re.compile('"[^"]*"')

def repl(mat, ri = re.compile('(?<!\\\\),') ):
    return ri.sub('\\\\',mat.group())

print ss
print repr(ss)
print
print      regx.sub(repl, ss)
print repr(regx.sub(repl, ss))

结果

"thing1,blah","thing2,blah","thing3\,blah",thing4 
'"thing1,blah","thing2,blah","thing3\\,blah",thing4 '

"thing1\blah","thing2\blah","thing3\,blah",thing4 
'"thing1\\blah","thing2\\blah","thing3\\,blah",thing4 '

【讨论】:

  • 此答案已被投票。我想知道为什么。我也很困惑,我的代表然后减少了 1 分而不是 2 分!
【解决方案3】:

你可以试试这个正则表达式。


>>> re.sub('(?<!"),(?!")', r"\\,", 
                     '"thing1,blah","thing2,blah","thing3,blah",thing4')
#Gives "thing1\,blah","thing2\,blah","thing3\,blah",thing4

这背后的逻辑是将,替换为\,,如果它的前后不是"

【讨论】:

  • 你的解决方案比我的好。你只需要写模式'([^"]+) *, *([^"]+)'甚至'([^"]+)[\t ]*,[\t ]*([^"]+)',以防逗号在空格之间
  • 添加了您提到的检查。谢谢!
  • 如何处理引号之间有两个逗号的字符串? "thing1,blah,moreblah"
  • @StevenRumbalski 是的,在这种情况下它不起作用。在这种情况下,必须同时使用前瞻和后瞻。我会看看我是否可以做出这些改变。
  • re.sub('".+?"', lambda m: m.group(0).replace(',','\\,'), '"th,ing1,blah","thing2,""blah""","thing3,blah",thing4') 怎么样?
【解决方案4】:

我想出了一个使用几个正则表达式函数的迭代解决方案:
finditer()、findall()、group()、start() 和 end()
有一种方法可以将所有这些转换为调用自身的递归函数。
有接盘侠吗?

outfile  = open(outfileName,'w')

p = re.compile(r'["]([^"]*)["]')
q = re.compile(r'([^\\])(,)')
for line in outfileRl:
    pg = p.finditer(line)
    pglen = len(p.findall(line))

    if pglen > 0:
        mpgstart = 0;
        mpgend   = 0;

        for i,mpg in enumerate(pg):
            if i == 0:
                outfile.write(line[:mpg.start()])

            qg    = q.finditer(mpg.group(0))
            qglen = len(q.findall(mpg.group(0)))

            if i > 0 and i < pglen:
                outfile.write(line[mpgend:mpg.start()])

            if qglen > 0:
                for j,mqg in enumerate(qg):
                    if j == 0:
                        outfile.write( mpg.group(0)[:mqg.start()]    )

                    outfile.write( re.sub(r'([^\\])(,)',r'\1\\\2',mqg.group(0)) )

                    if j == (qglen-1):
                        outfile.write( mpg.group(0)[mqg.end():]      )
            else:
                outfile.write(mpg.group(0))

            if i == (pglen-1):
                outfile.write(line[mpg.end():])

            mpgstart = mpg.start()
            mpgend   = mpg.end()
    else:
        outfile.write(line)

outfile.close()

【讨论】:

  • 您的代码非常曲折:您正在使用正则表达式来完成正则表达式的一小部分功能,以便通过精确的字符串方法获得执行处理的字符串元素正则表达式做了什么。顺便说一句,您没有注意到您的代码为 "thing3,blah" 提供了一个错误的结果,该结果被转换为 "thingx\x03,blah" ,我不知道不知道怎么做。
  • 另外,顺便问一下,您是否曾在任何时候表示,关于您为获得答案而准确提出的问题存在答案和辩论?您对我们希望有帮助的其他答案没有丝毫暗示。取而代之的是,您显示一个没有任何兴趣的代码,就好像您没有阅读答案一样。我觉得这有点不公平。
【解决方案5】:

你看过 str.replace() 吗?

str.replace(old, new[, count]) 返回所有出现的子字符串 old 的字符串副本 换成新的。如果给出了可选参数计数,则只有 第一次出现的次数被替换。

here 是一些文档

希望对你有帮助

【讨论】:

    猜你喜欢
    • 2016-07-21
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多