【问题标题】:Regex- replace sequence of one character with same number of another character正则表达式 - 用相同数量的另一个字符替换一个字符的序列
【发布时间】:2020-06-25 18:19:50
【问题描述】:

假设我有一个这样的字符串:

=====

我想用这个替换它:

-----

我只想在它的字符数超过一定数量时替换它(我们会说 > 3)。

所以,这些应该是替代品:

=== -> ===
==== -> ----
===== -> -----

应用程序是我想用 2 级标记替换 Markdown 中的所有 1 级标题标记,而不更改嵌入的代码块。

我知道我能做到:

/=/-/g,但这匹配任何带等号 (if (x == y)) 的内容,这是不可取的。

或者这个:

/===+/----/g,但这不考虑原始匹配字符串的长度。

这可能吗?

【问题讨论】:

  • 我故意忽略了它。我正在使用 vim 或 sed 进行正则表达式,但我想要一个可以应用于任何语言的通用解决方案。
  • 我认为在纯 RE 中没有通用的方法来做你想做的事。如下所述,各种实现都添加了允许它的功能,但没有任何东西可以在支持 RE 的所有东西上工作。
  • 所以我故意没有回答:-)。标签描述说因此,在提问时,请始终包含特定的编程语言或工具。
  • 关于 javascript 的同样问题:stackoverflow.com/questions/7456559/…

标签: regex replace


【解决方案1】:

Perl 可以做到:

my $string = "===== Hello World ====";
$string =~ s/(====+)/"-" x length($1)/eg;
# $string contains ----- Hello World ----

标志 /e 使 Perl 在 s/// 的第二部分执行表达式。 你可以用 oneliner 试试这个:

perl -e '$ARGV[0] =~ s/(====+)/"-" x length($1)/eg; print $ARGV[0]' "===== Hello World ===="

【讨论】:

  • 我喜欢这个的命令行版本。我仍然想要更通用的东西,但这解决了问题。
  • @tjameson,我不确定你是什么意思“更一般”,但你也可能喜欢正则表达式的缩短版本:s/(={3,})/"-" x length($1)/eg 其中={4,} 表示 4 个或更多字符
  • 我的意思不是 perl。适用于大多数正则表达式平台(sed、vim 等)的东西。无论如何,问题已经解决了,谢谢。
【解决方案2】:

取决于您使用的语言。基本上,在某些语言中,您可以将代码放在正则表达式的右侧,允许您执行以下操作:(这是在 perl 中):

s/(=+)/(length($1) > 3 ? "-" : "=") x length($1)/e

'e' 标志告诉 perl 执行表达式右侧的代码,而不是仅仅将其解析为字符串。

【讨论】:

  • 我没有使用语言。我只是使用 sed 或 vim 的正则表达式。不使用语言可以吗?
  • 很确定 vim 的语言足够好,可以让你做类似的事情 - 请参阅替换命令中的 \= 运算符。
  • @tjameson:你正在使用“一种语言”,无论你使用什么。此外,当perl -pe 's/foo/bar/g' 工作得更好时,我看不出任何人会使用sed -e 's/foo/bar/g' 的可能原因。 “试试吧,你会喜欢的!”
  • @tchrist- 从技术上讲,正则表达式可以识别一种语言。某些特性在正则表达式的实现中是通用的。这是我试图访问的那个子集。它与实现无关,而是与普遍接受的“标准”功能相关。我希望同样的东西在 sed、vim、perl、c++、javascript、python 等的 boost 中工作,除了可能有一点语法之外,没有太大的变化。话虽如此,我知道这个答案有其优点,但它是 Perl 特有的,这不是我所要求的。如果找不到更通用的解决方案,我会接受。
  • 如果您尝试坚持所有正则表达式实现的公共子集,您将受到限制。分组是 ( ) 或 ( ) 等
【解决方案3】:

我也在为这样的事情寻找一个纯正则表达式解决方案。我在 SO 上没有找到,所以我解决了。

短版:here 是正则表达式:

((?<====)=)|(=(?====))|((?<===)=(?==))|((?<==)=(?===))

这是我使用 R 的方式:

str <- " = == === ==== ===== ====== ======="

gsub("=(?====)",      "-", str, perl = TRUE) # (1) Pos. lookahead
gsub("(?<====)=",     "-", str, perl = TRUE) # (2) Pos. look-behing
gsub("(?<===)=(?==)", "-", str, perl = TRUE) # (3) Middle part for cases of 4 or 5 ='s (1/2)
gsub("(?<==)=(?===)", "-", str, perl = TRUE) # (4) Middle part for cases of 4 or 5 ='s (2/2)

# Combining all, we have:
gsub("((?<====)=)|(=(?====))|((?<===)=(?==))|((?<==)=(?===))", "-", str, perl = TRUE) # (5)

(1) = == === -=== --=== ---=== ----===
(2) = == === ===- ===-- ===--- ===----
(3) = == === ==-= ==--= ==---= ==----=
(4) = == === =-== =--== =---== =----==
(5) = == === ---- ----- ------ -------

不那么复杂的正则表达式的替代方法(但需要 3 个步骤)

# First, deal with 4 & 5 equal signs with negative look-behind and lookahead
str <- gsub("(?<!=)={4}(?!=)", "----",     str, perl = TRUE) # (2.1)
str <- gsub("(?<!=)={5}(?!=)", "-----",    str, perl = TRUE) # (2.2)

# Then use regex (3) from above for 6+ equal signs
str <- gsub("((?<====)=)|(=(?====))", "-", str, perl = TRUE) # (2.3)

(2.1) = == === ---- ===== ====== =======
(2.2) = == === ---- ----- ====== =======
(2.3) = == === ---- ----- ------ -------

【讨论】:

    【解决方案4】:

    特别是对于这个 Markdown 标题用例,您可以使用这些总是出现在行首的事实:

    /(^=|(?<==)=)/-/
    

    将替换行首或前面有一个“=”的所有“=”字符。

    它会在文本中删除双 '=='...也许有人可以改进它?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多