正则表达式替换 - 如何用不同的字符串替换多个相同模式的位置?

6

我是一个独特的问题..!

我有一个字符串,在多个位置上都有一些常量值。例如,考虑以下字符串。

string tmpStr = "Hello _tmp_ how is _tmp_ this possible _tmp_ in C#...?"

现在我想用存储在数组中的值替换字符串中的每个tmp,第一个tmp保存array[0],第二个tmp保存array[1],以此类推... 有什么好的方法吗? 我使用的是C#2.0。
4个回答

4
这个怎么样:
string input = "Hello _tmp_ how is _tmp_ this possible _tmp_ in C#...?";
string[] array = { "value1", "value2", "value3" };

Regex rx = new Regex(@"\b_tmp_\b");

if (rx.Matches(input).Count <= array.Length)
{
    int index = 0;
    string result = rx.Replace(input, m => array[index++]);
    Console.WriteLine(result);
}

您需要确保找到的匹配数永远不会大于数组的长度,如上所示。

编辑:针对评论,可以通过将lambda替换为以下内容轻松使用C# 2.0:

string result = rx.Replace(input, delegate(Match m) { return array[index++]; });

向您致敬,这正是我想要的。但它是如何工作的?您有一个lambda表达式m => array[index++],它是如何实现目的的? - Amit
@Amit:lambda表达式或匿名委托取代了MatchEvaluator的位置。每个找到的匹配项都将被数组的一个元素替换。因此,第一个匹配项将被替换为array [0],然后index ++将把index设置为1,然后下一个匹配项将被推进到array [1]的值,依此类推。 - Ahmad Mageed
@Ahmad:非常感谢..让我继续探索..!我的机器上安装了3.5框架,lambda表达式在指向2.0框架的项目上运行良好..! - Amit
@Amit:Martin Booth在下面的帖子中提出了一个非常好的观点。委托的真正原因是为了捕获“index”变量,以便可以为每个匹配正确地推进它。如果我仅使用array[index ++],那么它将被评估一次并重复使用value1,与问题的目标相反。您可能需要参考Jon Skeet关于闭包的文章以获取更多详细信息:http://csharpindepth.com/Articles/Chapter5/Closures.aspx - Ahmad Mageed
@AhmadMageed,只有一个问题。您确定您提供的MatchEvaluator中枚举匹配项的顺序将是从左到右严格执行的吗?换句话说,如果委托方法首先为第二个匹配项调用,然后再为第一个匹配项调用,那么在这种假设情况下,替换将被执行不正确。我知道从左到右的流程对于正则表达式实现来说很常见,但是,如果发生了什么怎么办?如果您有任何可以消除我的疑虑的链接,能否提供它们。 - tsionyx

2

1
建议,您可以使用 string.Split() 函数按 "tmp" 进行分割。然后遍历拆分后的列表并将它们与数组值一起打印出来。例如,伪代码示例:
string[] myarray = new string[] { 'val1', 'val2' };
string s = "Hello _tmp_ how is _tmp_ this possible _tmp_ in C#";
string[] items = s.Split("tmp");
for (int i = 0; i < items.Length; i++)
{
    Console.WriteLine(parts[i] + myarray[i] ) ;
}

1

我认为Ahmad Mageed的第一个解决方案是最好的,因为当传递到rx.Replace方法中时,array[index++]只会被评估一次。

我也编译了它来验证我是否正确理解了它,结果它产生了以下输出:

你好 value1 这怎么可能在C#中出现value1...

随着框架的后续版本,行为是否发生了变化?或者我认为预期的输出应该是:

你好 value1 这怎么可能在C#中出现value2...?


+1 给你,非常好的观点。你完全正确,这里已经太晚了 :) 我的第一个解决方案有效是因为 index 是一个捕获的值。现在回滚我的答案以反映这一点。 - Ahmad Mageed
@Martin:你的期望是正确的。那符合我的原始答案。如果我直接使用array[index++],框架的行为不会改变,就像我在回滚之前所做的那样。这确实会一遍又一遍地给出value1。第二种方法有效的原因是index变量被委托捕获了。有关更多信息,请参见Jon Skeet的有关闭包的文章:http://csharpindepth.com/Articles/Chapter5/Closures.aspx - Ahmad Mageed

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