You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Perl正则表达式可选匹配配对引号?

匹配带可选配对引号的配置项格式

我需要用单行正则处理文件内容替换,sed满足不了需求,改用Perl。目前能匹配setting = value # comment格式,拆分出setting = 、value和 # comment三个部分,示例命令:

perl -lne 'print "-1-$1-2-$2-3-$3-E-" if /^\s*(setting\s*=\s*)([^\s#]+)(\s*#\s*.*)?/'

执行后输出类似-1-setting = -2-value-3- # comment-E-。

现在遇到的问题是:value可能被单引号(')或双引号(")包裹,且前后引号必须一致。我尝试用反向引用匹配,但命令:

perl -lne 'print "-1-$1-2-$2-3-$3-4-$4-5-$5-E-" if /^\s*(setting\s*=\s*)(\N{APOSTROPHE}|\N{QUOTATION MARK})?([^\s#]+)(\2)?(\s*#\s*.*)?/'

存在问题:组3会捕获闭合引号,组4为空;而且Perl不支持在组3的否定断言里用反向引用。

我的思路方向:

  • 有没有匹配非指定字符串的断言形式?
  • 能否创建单个字符的捕获组,让它能在否定字符集中通过反向引用调用?
  • 能否引用反向引用的第一个字符?
  • 能否把反向引用当作字符集纳入否定集合?
  • 用环视断言,但只有正/反向环视,没有“当前环视”。

现在需要解决:Perl正则怎么实现这种可选配对引号的匹配?


解决方案:分支匹配+反向引用

可以通过分支结构分别处理「不带引号」和「带配对引号」的情况,同时用反向引用确保引号一致:

perl -lne 'print "-1-$1-2-$2-3-$3-E-" if /^\s*(setting\s*=\s*)(?:([^\s#"\']+)|(["\'])(.*?)\3)(\s*#\s*.*)?/'

正则解释:

  1. ^\s*(setting\s*=\s*):匹配配置项的前缀部分,捕获到组1(setting = )。
  2. (?:...):非捕获组,用来包裹两种情况的分支:
    • ([^\s#"\']+):第一种情况——不带引号的value,捕获到组2,匹配内容是不含空格、#、单双引号的字符序列。
    • (["\'])(.*?)\3:第二种情况——带配对引号的value:
      • (["\']):捕获开头的单/双引号到组3;
      • (.*?):非贪婪匹配引号内的内容(避免匹配到后面的引号),捕获到组2;
      • \3:反向引用组3的引号,确保结尾引号和开头一致。
  3. (\s*#\s*.*)?:可选的注释部分,捕获到组4(对应原来的组3)。

测试效果:

  • 对于setting = value # comment,输出-1-setting = -2-value-3- # comment-E-
  • 对于setting = 'quoted value' # comment,输出-1-setting = -2-quoted value-3- # comment-E-
  • 对于setting = "another value" # comment,输出-1-setting = -2-another value-3- # comment-E-

优化点说明:

  • 用非捕获组(?:...)分支处理两种情况,避免多余的捕获组干扰;
  • 非贪婪匹配.*?确保引号内的内容不会跨引号匹配;
  • 反向引用\3严格保证前后引号一致,不匹配单双引号混用的情况(比如'value"会被视为不匹配)。

如果需要支持引号内转义(比如"value with \"quote\""),可以把引号内的匹配部分改成(.*?(?<!\\)),不过如果你的场景不需要转义,上面的正则足够用。


内容的提问来源于stack exchange,提问作者Bernd Wechner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 15:33:37