Regex-返回匹配中的上一个AND下一个单词
本文关键字:上一个 AND 下一个 单词 返回 Regex- | 更新日期: 2023-09-27 18:21:34
我目前有两个独立的正则表达式模式来查找目标单词+下一个单词和目标单词+上一个单词:
string text = "Here is a test MYWORD statement for MYWORD regex";
string pattern = "(''bMYWORD''s)(''w+)"; //MYWORD statement; MYWORD regex
string pattern = "(''w+)(''s''bMYWORD)"; //test MYWORD; for MYWORD
regex是否提供了一种优雅的方法,可以将上面的两种模式组合起来用于单个调用?
感谢
编辑:非常感谢m.buettner和Qtax的精彩解释和示例-非常有用!
我尝试过提供的一些例子,这些例子在所需的上下文中与"MYWORD"匹配,但也许我还不够清楚:我正在尝试返回上面评论的所有短语,即:
Matches(pattern)应返回以下所有字符串:
'MYWORD statement'
'MYWORD regex'
'test MYWORD'
'for MYWORD'
如果我最初的问题没有很好地解释,我深表歉意!
在前瞻内进行匹配:
string pattern = @"'b(?=('w+'s+MYWORD|MYWORD's+'w+)'b)";
string[] result = Regex.Matches(text, pattern)
.Cast<Match>()
.Select(match => match.Groups[1].Value)
.ToArray();
此正则表达式在匹配时不使用任何字符,这使得重叠匹配成为可能。您不必担心无限循环,因为正则表达式引擎在开始寻找下一个匹配项之前会自动前进一个位置。拍摄组仍然像往常一样工作。
如果您需要像前面提到的其他响应程序一样处理字符串开头和结尾的匹配,那么应该这样做:
string pattern = @"'b(?=((?:^|'w+'s+)MYWORD|MYWORD(?:'s+'w+|$))'b)";
更新:一位评论者询问如何在不包括目标单词的情况下捕获前面和后面的单词。答案很简单但并不明显:
string pattern = @"'b(?=(('w+)'s+MYWORD|MYWORD's+('w+))'b)";
string[] result = Regex.Matches(text, pattern)
.Cast<Match>()
.Select(match => match.Groups[2].Value + match.Groups[3].Value)
.ToArray();
简单的部分是为单个单词添加捕获组。不明显的部分是意识到,在.NET中,如果捕获组不参与匹配,并且您访问了它的Value
属性,则会得到一个空字符串。我们知道两个小组中只有一个会参加每场比赛。我们不需要知道它是哪一个,我们只需要它的价值。串接字符串值可以提供我们想要的值。
但情况越来越好:
string[] result = Regex.Matches(text, pattern)
.Cast<Match>()
.Select(match => match.Result("$2$3"))
.ToArray();
Result()
方法没有得到太多使用,因为.NET的Regex API的其余部分设计得很好,但当它有用时,它就太棒了!
首先,一些建议:使用逐字逐句的字符串。他们让逃跑变得更容易对付:
string pattern = @"('bMYWORD's)('w+)"; //MYWORD statement; MYWORD regex
string pattern = @"('w+)('s'bMYWORD)"; //test MYWORD; for MYWORD
请注意,你的第二种模式在错误的一端有单词边界:
string pattern = @"('w+)('sMYWORD'b)"; //test MYWORD; for MYWORD
现在,天真的方法很简单:
string pattern = @"('w+)'s(MYWORD)'s('w+)";
这有一些问题。首先,它要求两个单词都在那里,所以如果MYWORD
出现在字符串的一端,就不会得到任何匹配。这可以通过允许锚而不是单词来解决:
string pattern = @"(?:('w+)'s|^)(MYWORD)(?:'s('w+)|$)";
现在还有一个问题。匹配项不能重叠。如果您有abc MYWORD def MYWORD ghi
,则第二个MYWORD
将不匹配。你可以通过使用lookarounds:从匹配中排除周围的单词来解决这个问题
string pattern = @"(?<=('w+)'s|^)(MYWORD)(?='s('w+)|$)";
如果你想允许匹配,既不在字符串的末尾,也没有相邻的单词(比如foo. MYWORD bar
,其中.
"屏蔽"了前一个单词)。只需将环视设置为可选即可。如果他们能匹配,他们将被包括在内,如果不能匹配,他们不会导致模式失败:
string pattern = @"(?<=('w+)'s)?(MYWORD)(?='s('w+))?";
工作演示。
对于您的示例,像这样简单的东西会起作用:
('w+)'sMYWORD's('w+)
但这需要MYWORD
的两边都有单词。
如果某些方面可能没有一个词,你可以让它们可选,比如:
(?:('w+)'s)?'bMYWORD'b(?:'s('w+))?
但这将匹配一个周围没有单词的MYWORD
如果你想在MYWORD
周围至少匹配一个单词,你可以使用:
(?:('w+)'sMYWORD'b(?:'s('w+))?|'bMYWORD's('w+))
这里右边的单词可能在第二组或第三组。