正则表达式模式选择在匹配引号之间的数据

6
假设我有以下字符串,我想在其上运行正则表达式:
This is a test string with "quotation-marks" within it.
The "problem" I am having, per-se, is "knowing" which "quotation-marks"
go with which words.

现在,假设我想用空格替换引号之间的所有-字符。我认为我可以通过以下正则表达式实现:

Find What:      (\"[^"]*?)(\-)([^"]*?\")
Replace With:   $1 $3

我遇到的问题是,使用这种模式时,它没有考虑引号是开放还是关闭的情况。
因此,在上面的示例中,per-se中的-字符将被替换为一个空格,因为它位于两个引号之间,但在一个闭合引号和一个开放引号之间 - 当我特别想查找在开放引号和闭合引号之间的文本
在这样一个正则表达式中如何解决这个问题?
我希望这样说起来让人能够理解。
我在使用VB / C# Regex。
只是为了完整起见(并希望必要时更详细地阐述),我希望最终得到的结果是:
This is a test string with "quotation marks" within it.
The "problem" I am having, per-se, is "knowing" which "quotation marks"
go with which words.

Thanks!!

5个回答

9
你遇到的问题与试图匹配HTML或开闭括号的人相同,正则表达式只能匹配常规语言,并且除了平凡情况外,它无法确定哪个 " 是结束符还是开始符。
编辑:正如Vasili Syrakis的答案所示,有时可以做到,但正则表达式对于这种类型的问题来说是一种脆弱的解决方案。
话虽如此,你可以将问题转化为平凡情况。由于你正在使用.NET,因此可以简单地匹配每个带引号的字符串并使用采用匹配评估器的重载
Regex.Replace(text, "\".*?\"", m => m.Value.Replace("-", " "))

测试:

var text = @"This is a test string with ""quotation-marks"" within it.
The ""problem"" I am having, per-se, is ""knowing"" which ""quotation-marks""
go with which words.";

Console.Write(Regex.Replace(text, "\".*?\"", m => m.Value.Replace("-", " ")));
//This is a test string with "quotation marks" within it.
//The "problem" I am having, per-se, is "knowing" which "quotation marks"
//go with which words. 

那绝对是一个酷炫的技巧!!! - 谢谢你分享!!!而且绝对 +1 - 尽管如此,我仍然很好奇是否可以直接用正则表达式来完成这个技巧。 - John Bustos
2
@JohnBustos:Vache是正确的,没有纯正的正则表达式解决方案不是hackish和脆弱的。你应该庆幸你使用的是一个正则表达式工具(.NET),它不仅支持lambda函数,而且使用起来非常容易。 - Alan Moore

6

相比正则表达式,一个常规方法可能更易于长期维护:

public static String replaceDashInQuotes(this string source, String newValue)
{
    StringBuilder sb = new StringBuilder();

    bool inquote = false;

    for (int i = 0; i < source.Length; i++)
    {
        if (source[i] == '\"')
            inquote = !inquote;

        if (source[i] == '-' && inquote)
            sb.Append(newValue);
        else
            sb.Append(source[i]);
    }

    return sb.ToString();
}

然后使用它:
var s = @"This is a test string with ""quotation-marks"" within it.
    The ""problem"" I am having, per-se, is ""knowing"" which ""quotation-marks""
    go with which words.";

MessageBox.Show(s.replaceDashInQuotes(" "));

谢谢,约翰 - 我知道我可以用一个方法来做到这一点(顺便说一句,这是一个不错的方法),但我更好奇如何使用正则表达式来实现这个功能,因为我认为这可能是我工具箱中必备的一件好东西。不过还是谢谢你! - John Bustos

6

我费了不少心思才解决这个问题,结果发现指定非单词边界\B就可以搞定:

正则表达式

\B("[^"]*)-([^"]*")\B

替换内容

$1 $2


演示

http://regex101.com/r/dS0bH8


我无法使其正常工作...另外,这是否考虑了匹配引号并仅在引号之间进行替换? - John Bustos
改了一下,现在试试看。 - Vasili Syrakis
哇 - 它起作用了!!!你真是太棒了 - 我要接受你的答案,但还有一个快速问题... 你知道如何更改它以考虑引号之间的多个“-”吗?还是那完全是一罐更丑陋的蠕虫? - John Bustos
嗯...我相信这是可能的,只是我不知道该怎么做 :P 我已经尝试了最后10分钟左右,因为我也想知道答案。 - Vasili Syrakis

1
我将把字符串按引号"作为分隔符拆分成字符串数组。然后,所有奇数索引的字符串都将是一对引号之间的字符串,只需在aSplittedString [oddIndex]上使用您的正则表达式,然后使用"连接整个数组。

酷点子!!!+1!!- 不过,如果可能的话,我仍然很好奇如何只使用正则表达式来实现这一点。 - John Bustos

1
你需要做的是明确地匹配引号内仅包含-的字符串。

使用此代码:

(\"[^"]*.*?)-(.*?\")

工作示例:http://regex101.com/r/jK5eL9

唯一的限制是它只适用于带引号的单个 word-word 实例。如果你有,比如说,"word-word, and word-word",它就会失败。


Remus,谢谢!!-不过有两个问题...我的第一个问题(我没有在问题中包含),如何更改以考虑引号之间的多个“-”。其次,更重要的是,这仍然会更改“per-se”,但它不应该:( - John Bustos
当你涉及到这样的条件问题时,最好像John Koerner建议的那样编写一个适当的函数。 - brandonscript
谢谢!- 我一直希望正则表达式有某种“向前查看”/“匹配”能力来获取那段文本,然后从上一个匹配结束的地方重新开始... - John Bustos
1
它确实可以,但处理多个捕获组并添加否定(对所有内容执行*除了...*)会变得非常繁琐且需要大量的处理开销(正则表达式很耗费资源)。 - brandonscript

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