【问题标题】:Using python to split a string with delimiter, while ignoring the delimiter and escape quotes inside quotes使用python用分隔符分割字符串,同时忽略分隔符和转义引号内的引号
【发布时间】:2011-03-01 04:15:19
【问题描述】:

我正在尝试根据分隔符的位置拆分字符串(我正在尝试从 Fortran 代码中删除 cmets)。我可以在以下字符串中使用! 进行拆分:

x = '''print "hi!" ! Remove me'''
pattern = '''(?:[^!"]|"[^"]*")+'''
y = re.search(pattern, x)

但是,如果字符串包含转义引号,则会失败,例如

z = '''print "h\"i!" ! Remove me'''

可以修改正则表达式来处理转义引号吗?或者我什至不应该使用正则表达式来解决这类问题?

【问题讨论】:

    标签: python regex delimiter


    【解决方案1】:

    这是一个经过验证的正则表达式(来自Mastering Regular Expressions),用于匹配可能包含反斜杠转义引号的双引号字符串:

    r'"[^"\\]*(?:\\.[^"\\]*)*"'
    

    在分隔引号内,它使用任何以反斜杠开头的字符对,而无需识别第二个字符;这允许它轻松处理转义的反斜杠和其他转义序列。在没有 possessive quantifiersatomic groups 的情况下,它也尽可能高效,Python 不支持它们。

    您的应用程序的完整正则表达式是:

    r'^((?:[^!"]+|"[^"\\]*(?:\\.[^"\\]*)*")*)!.*$'
    

    匹配包含 cmets 的行,并捕获组 #1 中注释之前的所有内容。对于以!开始的行,捕获可能是零长度。此正则表达式适用于sub 而不是search,如下所示:

    import re
    
    pattern = r'^((?:[^!"]+|"[^"\\]*(?:\\.[^"\\]*)*")*)!.*$'
    
    x = '''print "hi!" ! Remove me'''
    y = re.sub(pattern, r'\1', x)
    print(y)
    

    See it in action on ideone.com

    免责声明:此答案与 FORTRAN 无关,仅与遵循问题中指定规则的代码有关。我从未使用过 FORTRAN,而且我在过去一个小时左右找到的每一个参考资料似乎都描述了一种完全不同的语言。嗯!

    【讨论】:

      【解决方案2】:

      Fortran 解析实际上非常棘手(参见例如线程 here)。我非常不熟悉语法的细节,以及'!'可能发生。所以这里有一个想法:cmets 本身包含“!”的可能性有多大。 ?如果不太可能,您可以简单地删除最后一个“!”之后的所有内容在每一行:

      def cleanup(line):
        splitlist = line.split("!")
        if len(splitlist) > 1 and "\"" not in splitlist[-1]:
            return '!'.join(splitlist[:-1]).strip()
        else:
            return line
      

      这并不完美,但在最坏的情况下,您最终会留下一些部分 cmets。这绝不应该影响实际代码。

      编辑:

      看起来 NumPy 在 F2py package 中包含一个基于 python 的 Fortran 解析器。根据许可限制,您也许可以对其进行返工以可靠地解析“代码但不解析 cmets”。

      【讨论】:

        【解决方案3】:

        您需要的是一个否定的后向断言:(?<!...)

        例如:

        z = r'''print "h\"i!" ! Remove me'''
        pattern = r'''(?:[^!"]|(?<!\\)".*(?<!\\)")+'''
        y = re.search(pattern, z)
        
        print(y.group(0))
        


        输出:

        print "h\"i!" 
        



        正如 cmets 中所指出的,上面的表达式不会处理转义的反斜杠。它也不会处理 FORTRAN 中允许的单引号。这个也应该适用于这些情况(我认为):

         pattern = r'''(?:[^!"']|((?<!\\)"|(\\\\)+").*?((?<!\\)"|(\\\\)+")|((?<!\\)'|(\\\\)+').*?((?<!\\)"|(\\\\)+'))+'''
        

        这有点难看。 . .

        【讨论】:

        • 转义的反斜杠怎么样?
        • 这将处理转义的反斜杠:pattern = r'''(?:[^!"]|((?&lt;!\\)"|(\\\\)+").*?((?&lt;!\\)"|(\\\\)+"))+'''。但是 FORTRAN 允许单引号 (') 和双引号 ("),这根本不处理。总的来说,使用正则表达式可能不是最好的解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多