使用正则表达式在单引号字符串中转义所有双引号

3

可能是重复问题:
用正则表达式在单引号内转义双引号

我需要一个正则表达式(仅限其他语言!,最好是perl语法REGEX或PCRE语法REGEX),将所有位于单引号字符串内的双引号"替换为\ "。 这是一个示例字符串(文件的一部分):

var baseUrl = $("#baseurl").html();
var head = '<div id="finishingDiv" style="background-image:url({baseUrl}css/userAd/images/out_main.jpg); background-repeat: repeat-y; ">'+
'<div id="buttonbar" style="width:810px; text-align:right">';

(注意:它们不必成对出现,“someValueBetween”,因此在一个单引号字符串中可能存在不均匀数量的双引号。)
(最后一行应该是这样的结果:)
'<div id=\"buttonbar\" style=\"width:810px; text-align:right\">';

感谢您提前的帮助。 ***更新: 为了明确起见,我只需要一个正则表达式,而不是Perl程序。 正则表达式可以是Perl正则表达式语法或PHP PCRE语法(据我所知,这是与Perl正则表达式语法非常接近的语法)。 目标是您可以在支持正则表达式的搜索和替换菜单中运行正则表达式(例如Eclipse和PhpEd)! 换句话说,我想要一个正则表达式,将其放入搜索IDE字段中,以便准确地给出所有未转义的单引号字符串中的“”作为结果。 在eclipse的替换字段中,我只需放置\$1以对其进行转义。 它们应该在Regexbuddy或regex coach中工作,请让我测试它们。 至少这是计划 :)

正则表达式比对正则表达式字符串进行转义更容易 - 你是否在寻找一个能够转义带有“s”的正则表达式字符串的 JavaScript 函数? - Scott Stafford
不好意思,我特别要求一个正则表达式,而不是JavaScript、PHP或Perl函数。这应该是一个简单的正则表达式,可以检索出所有在单引号字符串中没有适当转义的 " 字符,然后将它们(可能是 $1 或其他内容)替换为 "。 - Tschef
3个回答

4

您需要的是Perl(或PCRE)翻译,其他内容不需要。

好的。

如果您只想转义未转义的双引号,无论其出现在何处,请执行以下操作:

  s{
      (?<! (?<! \\ ) \\{1} )
      (?<! (?<! \\ ) \\{3} )
      (?<! (?<! \\ ) \\{5} )
      (?<! (?<! \\ ) \\{7} )
      (?= " )
  }{\\}xg;

如果您想在未转义的单引号之间转义未转义的双引号,并且只有一对这样的单引号,请执行以下操作:

1 while s{

  (?(DEFINE)

    (?<unescaped>
      (?<! (?<! \\ ) \\{1} )
      (?<! (?<! \\ ) \\{3} )
      (?<! (?<! \\ ) \\{5} )
      (?<! (?<! \\ ) \\{7} )
    )

    (?<single_quote> (?&unescaped) ' )
    (?<double_quote> (?&unescaped) " )
    (?<unquoted>     [^'] *?          )

  )

  (?<HEAD>
    (?&single_quote)
    (?&unquoted)
  )

  (?<TAIL>
    (?&double_quote)
    (?&unquoted)
    (?&single_quote)

  )

}<$+{HEAD}\\$+{TAIL}>xg;

但是,如果您在每行中可能有多个成对未转义的单引号,并且您只想转义落在这些未转义单引号之间的未转义双引号,则可以执行以下操作:

sub escape_quote {
  my $_ = shift;
  s{
      (?<! (?<! \\ ) \\{1} )
      (?<! (?<! \\ ) \\{3} )
      (?<! (?<! \\ ) \\{5} )
      (?<! (?<! \\ ) \\{7} )
      (?= " )
  }{\\}xg;

  return $_;
}

s{

  (?(DEFINE)

    (?<unescaped>
      (?<! (?<! \\ ) \\{1} )
      (?<! (?<! \\ ) \\{3} )
      (?<! (?<! \\ ) \\{5} )
      (?<! (?<! \\ ) \\{7} )
    )

    (?<single_quote> (?&unescaped) ' )
    (?<unquoted>     [^'] *?          )

  )

  (?<HEAD> (?&single_quote) )
  (?<TARGET> (?&unquoted) )
  (?<TAIL> (?&single_quote) )

}{
               $+{HEAD}    .
  escape_quote($+{TARGET}) .
               $+{TAIL}

}xeg;

请注意,这一切都假设您没有合法的成对未转义的双引号中含有未转义的单引号。即使像这样的内容也会使您迷失方向:
my $cute = q(') . "stuff" . q(');

也许你需要使用一个适当的解析模块。

请不要注意所有花哨和欺骗性不正确的SO着色。由于某种原因,它似乎无法像perl一样解析Perl。我想象不出为什么。☺


看起来很不错啊!能否在RegexBuddy或Regex Coach中运行它,特别是在Eclipse中作为搜索替换正则表达式运行?(你是在为Perl工作吗?) - Tschef
好的,你有自己的维基百科条目。我必须说很令人印象深刻。我向你鞠躬 :) 在Eclipse搜索和替换部分,这个正则表达式需要帮助吗?不幸的是,我不能强制团队中的每个人都安装Perl。 - Tschef

2
根据您的编辑,您希望在未指定的IDE或文本编辑器的搜索和替换功能中使用通用正则表达式。这并不简单。我相信您已经意识到不同的语言(Perl、Java、Python等)往往具有自己的正则表达式风格,具有不同的功能集和语法怪异。编辑器和IDE之间的情况甚至更糟。
更新:自从我写这篇文章以来,Visual Studio已经切换到使用.NET风格,Notepad++也采用了Boost库。下面的正则表达式现在可以在我提到的所有编辑器/IDE中工作,除了Visual Studio。(.NET不支持占有量词,但它确实有原子组,可以用于相同的效果。)
JEdit和IntelliJ IDEA是用Java编写的,使用Java的正则表达式风格,非常好用。但是Visual Studio不使用优秀的.NET风格,而是使用具有折衷功能集和奇异语法的传统风格。苹果开发人员大力推荐的Mac编辑器TextMate使用功能丰富的Oniguruma风格,但是Notepad++(一个免费的Windows编辑器,也获得了很多好评)使用具有极其有限功能集的风格-它甚至不支持交替!
因此,即使是相对简单的任务,也可能因使用的编辑器而变得困难或不可能完成,但您正在尝试做的事情非常棘手。这是我为此想出的最简单的正则表达式:
搜索:\G((?:(?:\A|')[^']*+')?+[^'"]*+)"([^'"]*+)
替换:$1\\"$2
(这假定每个撇号都用作引号;没有需要忽略的撇号,因为它们在注释、双引号字符串或其他任何地方;文本中已经没有转义引号(单引号或双引号)等等。)
\G(上一个匹配的结尾锚点)是必不可少的,但是某些较流行的正则表达式风格(如JavaScript和Python)甚至不支持它。占有量词(*+、?+)使正则表达式在无法匹配时不会陷入困境;它们在PCRE、Oniguruma、Perl 5.10+和Java中可用。.NET没有它们,但它确实有稍微笨拙的替代方法-原子组。
我建议您放弃通用正则表达式方法,并标准化具有所需功能的工具集。对于一般目的,我认为没有什么比JGSoft工具系列更好了:EditPad Pro、PowerGrep和RegexBuddy。在功能和性能方面,JGSoft正则表达式风格与任何其他东西一样好;它所缺少的只是递归匹配和嵌入式代码功能。

p.s. 我看到你在评论中提到了Eclipse;我没有安装它,但我预计它使用Java的正则表达式风格(或可能是ICU风格,其语法与Java几乎相同),因此上面的正则表达式应该可以在其中工作。


这实际上很接近,但是使用\G并不起作用。它在正则表达式语法中有\G选项,但是它不能与之一起使用!如果我将其省略,它会弄乱正则表达式,因为它会转义所有的“,无论它们在哪里或是否在单引号中。有没有可能使这个语句逐行工作?我想那就足够了。 - Tschef
这是在Eclipse中吗?也许你需要以不同的方式转义。以下是在(正确工作的)Java代码中的样子:replaceAll("\\G((?:(?:\\A|')[^']*+')?+[^'\"]*+)\"([^'\"]*+)", "$1\\\\\"$2")我不会期望编辑器的搜索小部件需要所有这些转义,但也许... - Alan Moore
语法没问题,但在前面加上\G后,令人惊讶的是它找不到任何东西。根据Eclipse正则表达式语法,它支持\G和\A。其余部分都没问题,而且只有一个斜杠。 你能告诉我\G和\A具体是做什么的吗?其余部分我都能理解,尽管我自己永远也想不到 :) - Tschef

0
只要每行只有一个单引号字符串(就像你的示例一样),这个命令应该可以工作(使用sed语法):
s|'\([^'"]*\)"\([^']*\)'|'\1\"\2'|g

@Downvoter:我认为使用一个正则表达式是最好的解决方案。 - thejh
这是一个无效的Perl正则表达式,或者至少是一个不正确和不明智的正则表达式。首先,在替换操作的右侧不应该放置\1等内容。其次,如果您希望填充捕获组,则不应该在左侧转义括号。第三,有许多情况您没有考虑到。 - tchrist
非常遗憾,在RegexBuddy中使用Perl语法根本无法工作。我不明白捕获组应该如何在它们前面加上\。但我希望能够理解它。 - Tschef
@Tschef:至少在GNU sed 4.2.1中,您必须转义括号以赋予它们特殊的含义。 - thejh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接