如何分别替换组的每个捕获?
我有一个正则表达式,它在捕获中使用GroupCollection
来捕获一组项目标识(可以用逗号分隔,也可以用最后一个词来表示“and”):
(bItem #(?<ITEMID>d+))|(,s?(?<ITEMID>d+))|(,?sands(?<ITEMID>d+))
有没有一种简单的方法使用C#的正则Regex
类来替换ITEMID号码的URL? 现在,我有以下几点:
foreach (Match match in matches)
{
var group = match.Groups["ITEMID"];
var address = String.Format(UnformattedAddress, group.Value);
CustomReplace(ref myString, group.Value, address,
group.Index, (group.Index + group.Length));
}
public static int CustomReplace(ref string source, string org, string replace,
int start, int max)
{
if (start < 0) throw new System.ArgumentOutOfRangeException("start");
if (max <= 0) return 0;
start = source.IndexOf(org, start);
if (start < 0) return 0;
var sb = new StringBuilder(source, 0, start, source.Length);
var found = 0;
while (max-- > 0)
{
var index = source.IndexOf(org, start);
if (index < 0) break;
sb.Append(source, start, index - start).Append(replace);
start = index + org.Length;
found++;
}
sb.Append(source, start, source.Length - start);
source = sb.ToString();
return found;
}
我在网上找到的CustomReplace
方法是一种简单的方法,用一个字符串源中的另一个字符串替换一个字符串。 问题是我确信可能有更简单的方法,可能使用Regex
类来根据需要替换GroupCollection
。 我无法弄清楚那是什么。 谢谢!
示例文本:
Hello the items you are looking for are Item #25, 38, and 45. They total 100 dollars.
25
, 38
和45
应该与我创建的URL字符串(这是一个HTML字符串)所取代。
你的模式适用于你的输入,但它确实有一个错误。 具体来说,它会匹配输入中出现在逗号或单词“和”后面的任何数字。
我继续并重写了你的模式以避免这个问题。 为了实现这一点,我实际上使用了两种正则表达式模式。 可以使用一种模式来解决这个问题,但它比我选择分享的方法相当复杂,可读性差。
主要模式是: bItem #d+(?:,? d+)*(?:,? and d+)?
这里没有使用捕获组,因为我只对匹配项目感兴趣。 (?: ... )
位是一个非捕获组。 (?:,? d+)*
的用法是在字符串的中间部分匹配多个逗号分隔值。
一旦项目匹配,我使用Regex.Replace
格式化项目,然后重新构建字符串以用格式化项目替换原始项目。
以下是一些有关不同输入的示例:
string[] inputs =
{
"Hello the items you are looking for are Item #25, 38, 22, and 45. They total 100 dollars.",
"... Item #25, 38 and 45. Other numbers 100, 20, and 30 untouched.",
"Item #25, and 45",
"Item #25 and 45",
"Item #25"
};
string pattern = @"bItem #d+(?:,? d+)*(?:,? and d+)?";
string digitPattern = @"(d+)";
// $1 refers to the first (and only) group in digitPattern
string replacement = @"<a href=""http://url/$1.html"">$1</a>";
foreach (var input in inputs)
{
Match m = Regex.Match(input, pattern);
string formatted = Regex.Replace(m.Value, digitPattern, replacement);
var builder = new StringBuilder(input)
.Remove(m.Index, m.Length)
.Insert(m.Index, formatted);
Console.WriteLine(builder.ToString());
}
如果您需要使用现有方法来格式化URL,而不是使用正则表达式替换模式,则可以使用接受MatchEvaluator
的Regex.Replace
重载。 这可以使用lambda来实现,并且比MSDN文档中显示的繁琐方法更好。
例如,假设您有一个FormatItem
方法接受一个字符串并返回一个格式化的字符串:
public string FormatItem(string item)
{
return String.Format("-- {0} --", item);
}
要使用FormatItem
,可以使用以下代码更改早期代码示例中使用的Regex.Replace
方法:
string formatted = Regex.Replace(m.Value, digitPattern,
d => FormatItem(d.Value));
这里是所需语法的一个例子,同时也表明您可以通过回调将其放回到C#中。
MatchEvaluator在Regex.Replace中如何工作?
你似乎一次从两个方向来到这里。 一方面,你有一个带有三个捕获组的正则表达式,所以你期望解决方案涉及一个GroupCollection。 另一方面,所有三个组都有相同的名称,所以也许你必须将它们作为同一组的单独捕获 - 即CaptureCollection。 实际上,你可能不需要他们中的任何一个。 这是你的正则表达式(经过一些美学调整):
string source = @"Total cost for Item #25, 38, and 45 is 100 dollars.";
Regex regex1 = new Regex(
@"bItem #(?<ITEMID>d+)|,s*(?<ITEMID>d+)|,?s+ands+(?<ITEMID>d+)",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
foreach (Match m in regex1.Matches(source)) {
Console.WriteLine(m.Groups["ITEMID"].Value);
}
它输出25
, 38
, 45
按预期方式。 每个选项都有自己的捕获组副本,但其中只有一个参与每场比赛。 这是.NET正则表达式的一个显着特征; 其他一些提供特殊的设置或组构造,允许您重用组名,但没有一个使它像.NET一样简单。 但是,在这种情况下,你并不需要它。 你可以像这样合并替代方案:
@"(bItem #|,s*|,?s+ands+)(?<ITEMID>d+)"
然而,你的正则表达式有一个问题,如果将源字符串更改为:
@"Total cost for Item #25, 38, and 45 is 1,500 dollars and 42 cents."
现在的输出是25
, 38
, 45
, 500
, 42
。 为了防止这些误报,您需要确保每个不以Item #
开头的比赛,从最后一场比赛结束时开始。 为此,您可以使用G
:
@"(bItem #|G,?s+ands+|G,s*)(?<ITEMID>d+)"
(为了效率的缘故,我也换了最后两个选项的顺序。)把所有这些放在一起,我们只有另一个正则表达式替换。
string source =
@"Total cost for Item #25, 38, and 45 is 1,500 dollars and 42 cents.";
Regex regex2 = new Regex(
@"(?<TEXT>bItem #|G,?s+ands+|G,s*)(?<ITEMID>d+)",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
string result = regex2.Replace(source,
@"${TEXT}<a href='URL_${ITEMID}'>${ITEMID}</a>");
Console.WriteLine(result);
不需要明确使用GroupCollections或CaptureCollections,除非您的替换比这更复杂,可能也不需要MatchEvaluator。
链接地址: http://www.djcxy.com/p/74811.html上一篇: How to replace each Capture of a Group individually?
下一篇: Referencing nested groups in JavaScript using string replace using regex