【问题标题】:Regex replace, but only between two patterns正则表达式替换,但仅在两种模式之间
【发布时间】:2009-03-03 21:33:59
【问题描述】:

好的,我正在尝试清理一个多行字符串。

每一行可能是也可能不是大块引用文本的一部分。示例:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted
and so is this one
and so is this one.”
This is not quoted “but this is
and so is this.”

我需要一个正则表达式替换来解开硬包装的引号行,即用空格替换 "\r\n",但只能在大引号之间。

更换后的外观如下:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted and so is this one and so is this one.”
This is not quoted “but this is and so is this.”

(注意最后两行是输入文本中的多行。)

约束

  • 理想情况下需要一个正则表达式替换调用
  • 使用 .NET RegEx 库
  • 引号总是开始/结束大引号,而不是普通的双引号 ("),这应该会更容易一些。

重要约束

这不是直接的 .NET 代码,我正在填充一个“searchfor/replacewith”字符串表,然后通过 RegEx.Replace 调用这些字符串。我无法添加自定义代码,如匹配评估器、循环捕获的组等。

到目前为止的当前答案,大致如下:

r.Replace("(?<=“)\r\n(?=”)", " ")

显然,我还没有接近。

同样的逻辑可以应用于编程代码中块 cmets 的颜色编码——块注释内的任何内容都不会与 cmets 之外的内容相同。 (代码有点棘手,因为开始/结束块注释分隔符也可以合法地存在于文字字符串中,我不必在这里处理这个问题。)

【问题讨论】:

  • 您能否提供限制的任何原因,尤其是前两个?
  • 添加...这不是自定义代码,它是我编写的通用解析/清理工具,它是从数据库表驱动的。没有一种简单的方法可以为这个特定问题编写一次性代码。

标签: .net regex replace


【解决方案1】:

假设所有大引号都正确平衡,这个正则表达式应该做你想做的事:

@"[\r\n]+(?=[^“”]*”)"

[\r\n]+ 将匹配任何类型的一个或多个行分隔符——Unix (\n)、DOS (\r\n) 或旧版 Mac (\r)。然后前瞻断言前面有一个封闭引号,并且在此处和那里之间没有开放引号。那么你的替换文本可以是一个简单的空格字符。

【讨论】:

  • 替换将是一个由单个空格字符组成的字符串。被替换的只是行分隔符。
  • 在这种情况下,我可以假设弯引号是适当平衡的。天才,艾伦。我知道必须有一些东西可以在没有递归的情况下工作......
【解决方案2】:

注意:对于测试正则表达式,我使用http://gskinner.com/RegExr/,这非常有用。

我认为您不能编写一个表达式来替换未定义数量的换行符。但是,您可以编写一个表达式来替换一个或多个,然后重复运行它或编写它来处理一个引用部分中的最大换行数。

首先,您需要单行模式,以便您的表达式匹配整个输入字符串,而不是逐行匹配。将其放在表达式的开头以将其打开:

(?s)

然后,您需要一个后向表达式来匹配起始引号:

(?<=“)

还有一个与结尾引号匹配的前瞻:

(?=”)

现在是匹配一些文本的表达式,然后是换行符,然后是一些文本:

([^”\r]*)\r?([^”\r]*)

请注意,换行符周围的文本位有两个捕获组,因此您可以在替换表达式中包含该文本。这将匹配引号内只有一个换行符的文本。要将其扩展到两个换行符,只需添加另一个可选换行符和可选的以下文本:

(?s)(?<=“)([^”\r]*)\r?([^”\r]*)\r?([^”\r]*)(?=”)

您可以扩展它以匹配您认为可能出现的尽可能多的换行符。不完美,但也许足够了。或者,如果您可以在文本上重复运行表达式,则只需一次替换一个。

让你的表达方式如下:

r.Replace("(?s)(?<=“)([^”\r]*)\r?([^”\r]*)", "$1 $2")

(这不太正确,因为即使第二组不匹配,它也会在文本后添加一个空格......但这是一个开始)

【讨论】:

  • 一种优雅的蛮力形式......好主意。不幸的是,可能有几百行文本需要在大引号之间连接。艾伦在下面的回答成功了。
【解决方案3】:

所以要做的就是找到一个以开引号开头的字符串,然后是一个 包含右引号或任何 \r \n 字符的字符串,然后是一个一系列一个或多个 \r \n 字符,捕获除终端 \r \n 字符之外的所有字符,并将整个匹配替换为捕获的部分。

-- MarkusQ

【讨论】:

  • 所以,你的建议是这样的: (“[^\r”]+)\r\n 替换为 $1[ ] 关闭!这将捕获引用文本中的第一个换行符,但不会捕获任何其他...替换不是递归的。
【解决方案4】:

我认为最简单的方法是将引用的部分与“(?s:.*?)” 匹配并使用MatchEvaluator 删除任何换行符。 MatchEvaluator 代码可以很简单

Replace(@"\s+", " ");

当然,您可以改进它以仅匹配实际包含换行符的引用部分,并仅替换这些部分中的换行符而不是所有空格,但这可能不值得。

【讨论】:

  • 我正在编写一组 RegEx 调用,所有这些调用都是从表中按特定顺序进行的,而不是在这里编写自定义代码。
  • 好的,那看看我的其他回答。
【解决方案5】:

你不能在你描述的范围内做你想做的事。

证明:

  • 您的固定替换表将执行固定数量的替换调用(调用此 n)
  • 每次替换只能消除固定数量的换行符(将此数字称为 m)。

因此

  • 将无法正确处理带有 m*n+1 换行符的引用块。

您要么需要提高设置的能力(例如,通过允许更复杂的替换、递归替换、无限重复标志,还是...?),要么接受您的引擎无法完成此任务的事实.

-- MarkusQ

【讨论】:

  • 如果我需要检查平衡的报价,我认为您对各种建议的了解越多。 Alan 提出了一个基于我的特定用例的答案,我可以依赖平衡的报价。感谢大家的帮助!
猜你喜欢
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 2022-12-24
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多