【问题标题】:Using regex to find a double quote within string encased in double quotes使用正则表达式在双引号中的字符串中查找双引号
【发布时间】:2015-01-22 14:29:35
【问题描述】:

我正在使用带有正则表达式的 ultraedit。我想查找(并替换)和嵌入的双引号,该双引号包含在以双引号开头/结尾的字符串中。这是一个带有管道的文本文件 |作为分隔符。

如何找到嵌入的双引号:

“这个字符串没问题。”|“这是一个中间带“C”双引号的例子。”|“下一行”

我最终需要将“C”中的双引号替换为只有 C。

【问题讨论】:

    标签: regex ultraedit


    【解决方案1】:

    对于您刚刚给出的示例,"\w" 用作查找 "C" 的正则表达式

    试试here

    替换机制可能内置在ultraedit中

    【讨论】:

      【解决方案2】:

      你真的不想用正则表达式来做这件事。您应该使用可以理解管道分隔符的 csv 解析器。如果我只使用正则表达式,我会像这样使用多个替换:

      查找并用占位符替换好的引号到文本。开始/结束报价:

       s/(^"|"$)/QUOTE/g
      

      管道分隔符附近的引号:

      s/"\|"/DELIMITER/g
      

      现在只保留嵌入的双引号。要全部删除:

      s/"//g
      

      现在把好的引号放回去:

      s/QUOTE|DELIMITER/"/g
      

      【讨论】:

        【解决方案3】:

        试试这个发现:

        (["][^"]*)["]C["]([^"]*["])
        

        并替换:

        \1C\2
        

        在 Perl 模式下开启正则表达式。

        截图

        UltraEdit Professional Text/HEX Editor 
        Version 21.30.0.1005
        

        试一试。

        开始于:

        "This string is ok."|"This is example with a "C" double quoted grade in middle."|"Next line"
        "This string is ok."|"This is example with a C double quoted grade in middle."|"Next line"
        

        结尾:

        "This string is ok."|"This is example with a C double quoted grade in middle."|"Next line"
        "This string is ok."|"This is example with a C double quoted grade in middle."|"Next line"
        

        正则表达式 FIND 的分解。

        第一部分。

        (["][^"]*)
        from (["][^"]*)["]C["]([^"]*["])
        

        这会查找以下序列:

        1. 双引号:["]
        2. 不是双引号的任意数量的字符:[^"]*
        3. ["][^"]* 周围的括号表示正则表达式引擎应存储此字符序列,以便 REPLACE 部分可以引用它(作为反向引用)。
        4. 请注意,这在开头和结尾重复 - 表示存储了 两个 序列。

        第二部分。

        ["]C["]
        from (["][^"]*)["]C["]([^"]*["])
        

        这会查找以下序列:

        1. 双引号:["]
        2. 大写字母 C(可能代表也可能不代表 Cookie)。
        3. 双引号:["]

        正则表达式 REPLACE 的分解。

        \1C\2
        
        1. \1 是一个反向引用,这意味着将其替换为保存的第一个序列
        2. 大写字母 C(可能代表也可能不代表 Cookie)。
        3. \2 是一个反向引用,这意味着将其替换为保存的第二个序列

        【讨论】:

          【解决方案4】:

          nanny 发布了一个很好的解决方案,但对于 Perl 脚本,不适用于 UltraEdit 等文本编辑器。

          通常可以在字段值中使用双引号。但是每个双引号必须用另外一个双引号进行转义。例如,在有关 comma-separated values 的维基百科文章中对此进行了解释。

          这种非常简单的转义算法使得在 CSV 文件中逐个字符地读取以编程语言编码的字符变得非常容易。但是双引号中包含的双引号、分隔符和换行符对于 CSV 文件中的正则表达式查找和替换来说是一场噩梦。

          我在 UltraEdit 宏中记录了几个替换

          InsertMode
          ColumnModeOff
          Top
          PerlReOn
          Find MatchCase RegExp "^"|"$"
          Replace All "QuOtE"
          Find MatchCase ""|"
          Replace All "QuOtE|"
          Find MatchCase "|""
          Replace All "|QuOtE"
          Find MatchCase """"
          Replace All "QuOtEQuOtE"
          Find MatchCase """
          Replace All """"
          Find MatchCase "QuOtE"
          Replace All """
          

          第一个替换是 Perl 正则表达式替换。行首或行尾的每个双引号都被字符串 QuOtE 替换。我很确定 CSV 文件中不存在 QuOtE

          管道字符前后的每个双引号也被 QuOtE 替换为接下来的 2 个非正则表达式替换。

          CSV 文件中的转义双引号 "" 接下来被 QuOtEQuOtE 替换为非正则表达式替换。

          现在将剩余的单双引号替换为两个双引号,以使其在 CSV 文件中有效。当然,您也可以删除那些单双引号。

          最后,所有 QuOtE 都被替换回双引号。

          注意:这不是最终的解决方案。然而,这些替换可能会产生错误的结果,例如对于像这样一个已经有效的 CSV 行

          "first value with separator ""|"" included"|second value|"third value again with separator|"|fourth value contains ""Hello!"""|fifth value
          

          结果是

          "first value with separator """|""" included"|second value|"third value again with separator|"|fourth value contains ""Hello!"""|fifth value
          

          PS:上面的有效示例行应该在电子表格应用程序中显示为

          first value with separator "|" included    second value    third value again with separator|    fourth value contains "Hello!"    fifth value
          

          【讨论】:

            【解决方案5】:

            CSV 的最大权衡是在每种情况下都正确解析而不是简单。 这是一种适度适度的方法。如果你有真正狡猾的字符串,其中的管道旁边有引号,你最好使用像 PERL 和 Text::CSV 这样的东西。

            正则表达式需要在引号的每一侧(例如[^|])都有一个非管道字符,因为解析器将吸收C,然后找不到旁边的另一个引号C.

            只要您的实际 CSV 字符串中没有相邻的管道和引号,此示例就可以很好地工作。前瞻和后随是零宽度,因此它们不会删除除引号之外的任何其他字符。

               1     2       3    4
            (?<!^)(?<!\|)"(?!\|)(?!$)
            
            1. 不要匹配行首的引号。
            2. 不要将引号与前面的管道相匹配。
            3. 之后不要将引号与管道匹配。
            4. 不要匹配字符串末尾的引号。

            每个匹配的引用都可以删除。不要忘记指定全局替换以获取所有引号。

            【讨论】:

            • 是的,这个 Perl 正则表达式具有 2 次后向和 2 次前瞻,非常适合在值中查找双引号。因此,它非常适合手动检查。我不会将它用于全部替换操作,因为它还发现了转义的双引号。但它非常适合手动搜索和替换。如果左侧或右侧还有一个双引号,(?&lt;!^)(?&lt;!["|])"(?!["|])(?!$) 将忽略双引号。但这会导致在已经引用的值的开头或结尾处也忽略单个双引号,例如 xx|"I replied: "Thanks!""|yy
            • 当我在 Ultra Edit 21.30 中运行这个替换时,它产生了我认为正确的结果:xx|"我回答:谢谢!"|yy
            • 您的正则表达式将xx|"I replied: "Thanks!""|yy 重新格式化为xx|"I replied: Thanks!"|yy,如果需要删除值中的双引号,这当然是正确的。但它也将xx|"I replied: ""Thanks!"""|yy 重新格式化为xx|"I replied: Thanks!"|yy,尽管 value 中的双引号已经用双引号正确转义,因此不应删除。通过在第一个示例中插入额外的双引号并保持已经正确格式化的第二个示例,我的宏适用于两个 CSV 行。如果目标是删除值中的所有双引号,则您的表达式效果最佳。
            • 看看原来的问题:我最终需要将“C”中的双引号替换为只有 C。听起来像我想要的。您正在“每次都完美解析”的方向进行调整,虽然有效的追求并不是问题所在。
            • 我知道提问者只是要求在已经用双引号括起来的值内查找(并替换)双引号。这就是我写你的表达在这里有效的原因,也是我赞成你的答案的原因。但是其他访问者可能只想在没有被双引号转义的值中找到双引号,这就是我的 cmets 的原因。这些 cmets 对您的解决方案没有任何批评。它们只是附加组件,解释了值中正确的转义双引号会发生什么以及可以采取哪些措施来避免它(部分)。
            猜你喜欢
            • 1970-01-01
            • 2013-10-01
            • 2017-06-18
            • 2012-03-20
            • 2017-06-04
            • 1970-01-01
            • 2012-09-10
            • 2016-08-20
            • 2018-01-25
            相关资源
            最近更新 更多