我有一个正则表达式,在其捕获中使用GroupCollection
来捕获一组项目ID(可以用逗号分隔,也可以考虑最后一个用'和'这个词):
(\bItem #(?<ITEMID>\d+))|(,\s?(?<ITEMID>\d+))|(,?\sand\s(?<ITEMID>\d+))
使用C#的Regex
类是否可以通过网址替换ITEMID号码?现在,我有以下内容:
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
应替换为我正在创建的网址字符串(这是一个HTML字符串)。
答案 0 :(得分:2)
您的模式适用于您的输入,但确实存在错误。具体来说,它会匹配输入中出现在逗号或单词“和”之后的任何数字。
我继续重写你的模式以避免这个问题。为实现这一目标,我实际上使用了两种正则表达式模式。可以使用一种模式来解决这个问题,但它比我选择分享的方法相当复杂且可读性差。
主要模式是:\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());
}
如果您需要使用现有方法格式化网址,而不是使用正则表达式替换模式,则可以使用接受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));
答案 1 :(得分:0)
这里是一个所需语法的示例,并且还显示您可以通过回调在替换中退回到C#。
答案 2 :(得分:0)
你好像是从两个方向同时来到这里。一方面,你有一个带有三个捕获组的正则表达式,所以你希望解决方案涉及一个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+and\s+(?<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+and\s+)(?<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+and\s+|\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+and\s+|\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。