正则表达式 C# 用多个结果替换匹配的字段
Regex C# replace matched fields with multiple results
我有这段文字:
iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)
我可以对文本(下方)进行正则表达式以获得 |
字符之间的所有元素的集合。我得到 18 场比赛,比赛 #1 是 |,|
MatchCollection fields = Regex.Matches(str, @"\|.*?\|");
然后我想用 ~0~
、~1~
、~2~
等占位符替换每个匹配项,直到 ~17~
这样我就可以 运行 我的其余代码。我不在乎是否所有常用文本都替换为相同的占位符,如果我使用所有 18 个,这会在占位符中留下空白。
我的问题是我不能直接替换字符串 |Jeddah, Saudi Arabia|,|,|
的这一部分中的元素 #1 (|,|
) 将替换它找到的第一个实例,其中正则表达式正确地将 |Jeddah, Saudi Arabia|
识别为一个匹配项,将 |,|
识别为另一个匹配项。
我求的结果是这样的:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~2~ & ~3~) & ~4~ & iif(instr(~5~,~1~)>0,~5~,~5~ & ~2~ & ~6~) & iif(~5~=~7~,~7~,~8~ & ~5~)
一旦我知道我有多少匹配项,就会在我构建的数组中增加数字。我保留原始值并稍后将它们交换回来,这是简单的部分。
\|,\|(?=[^(|]*(\|[^(|]*\|)*[^(|]*\))
您可以使用 lookahead
来检查 |,|
被捕获以替换 )
之前是否没有遗漏 |
。参见演示。
嗯...有点难以解释,但基本上是根据您所获得的构建...
鉴于 匹配项 ,我将它们添加到列表中并使用 Distinct
LINQ 函数获得唯一的匹配项,并使用 OrderBy
从最长到最短的顺序对它们进行排序LINQ 函数。然后循环遍历生成的 RouteMap 并替换原始字符串。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var input = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
Console.WriteLine(input);
var re = new Regex(@"\|.*?\|");
var matches = re.Matches(input);
var mz = new List<string>();
foreach(Match m in matches)
{
mz.Add(m.Groups[0].ToString());
}
var routeMap = mz.Distinct().OrderByDescending(n => n.Length).ToList(); //Get distinct, and sort it longest to shortest... need it this way or it won't do the replacement correctly.
for (var i = 0; i < routeMap.Count; i++)
{
input = input.Replace(routeMap[i], string.Format("~{0}~", i));
}
Console.WriteLine(input);
Console.WriteLine();
Console.WriteLine("The route map replacement key:");
var idx = 0;
routeMap.ForEach(m => Console.WriteLine("{0}: {1}", idx++, m));
}
}
运行 样本位于:https://dotnetfiddle.net/PIuuae
我想出了一个建议来获得你的第二个输出选项。
您可以使用 MatchEvaluator
将匹配传递给单独的方法,并在该方法中增加一个 "global" 计数器:
public string ReplaceMatch(Match m)
{
i++;
return "~" + i.ToString() + "~";
}
public static int i = -1;
// ... then, in your calling method
var txt = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var fields = Regex.Matches(txt, @"\|.*?\|");
var txt2 = Regex.Replace(txt, @"\|.*?\|", new MatchEvaluator(ReplaceMatch));
输出:
iif(instr(~0~,~1~)>0,~2~,~3~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~8~)>0,~9~,~10~ & ~11~ & ~12~) & iif(~13~=~14~,~15~,~16~ & ~17~)
与这些占位符对应的匹配值保存在 fields
变量中,因此稍后您将能够匹配它们。
编辑:对于选项 1(这是您编辑问题后的唯一选项),答案是创建一个包含不同项目的字典,并在替换中使用它方法:
var txt = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var fields = Regex.Matches(txt, @"\|.*?\|").Cast<Match>().Select(p=> p.Value).Distinct().Select((s, i) => new { s, i }).ToDictionary(x => x.s, x => x.i);
var txt3 = Regex.Replace(txt, @"\|.*?\|", m => string.Format("~{0}~", fields[m.Value]));
输出:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~2~ & ~3~) & ~4~ & iif(instr(~5~,~1~)>0,~5~,~5~ & ~2~ & ~6~) & iif(~5~=~7~,~7~,~8~ & ~5~)
我会使用一些 lambda 函数:
// This one gets the index from the list of matches
private static string LookupReplace(string text, List<string> newList)
{
var result = "~" + newList.IndexOf(text).ToString() + "~";
return result;
}
// This one just increments a global counter
private static string NumberedReplace()
{
i++;
return "~" + i.ToString() + "~";
}
public static int i = -1;
public static void Main()
{
string text = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var re = new Regex(@"\|.*?\|");
var newList = re.Matches(text)
.OfType<Match>()
.Select(m => m.Value)
.ToList();
// First replace with index
string result = re.Replace(text, x => LookupReplace(x.Value, newList));
Console.WriteLine(result);
// Second replace with counter
result = re.Replace(text, x => NumberedReplace());
Console.WriteLine(result);
}
每次替换的输出:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~1~)>0,~7~,~7~ & ~4~ & ~12~) & iif(~7~=~14~,~14~,~16~ & ~7~)
iif(instr(~0~,~1~)>0,~2~,~3~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~8~)>0,~9~,~10~ & ~11~ & ~12~) & iif(~13~=~14~,~15~,~16~ & ~17~)
我有这段文字:
iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)
我可以对文本(下方)进行正则表达式以获得 |
字符之间的所有元素的集合。我得到 18 场比赛,比赛 #1 是 |,|
MatchCollection fields = Regex.Matches(str, @"\|.*?\|");
然后我想用 ~0~
、~1~
、~2~
等占位符替换每个匹配项,直到 ~17~
这样我就可以 运行 我的其余代码。我不在乎是否所有常用文本都替换为相同的占位符,如果我使用所有 18 个,这会在占位符中留下空白。
我的问题是我不能直接替换字符串 |Jeddah, Saudi Arabia|,|,|
的这一部分中的元素 #1 (|,|
) 将替换它找到的第一个实例,其中正则表达式正确地将 |Jeddah, Saudi Arabia|
识别为一个匹配项,将 |,|
识别为另一个匹配项。
我求的结果是这样的:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~2~ & ~3~) & ~4~ & iif(instr(~5~,~1~)>0,~5~,~5~ & ~2~ & ~6~) & iif(~5~=~7~,~7~,~8~ & ~5~)
一旦我知道我有多少匹配项,就会在我构建的数组中增加数字。我保留原始值并稍后将它们交换回来,这是简单的部分。
\|,\|(?=[^(|]*(\|[^(|]*\|)*[^(|]*\))
您可以使用 lookahead
来检查 |,|
被捕获以替换 )
之前是否没有遗漏 |
。参见演示。
嗯...有点难以解释,但基本上是根据您所获得的构建...
鉴于 匹配项 ,我将它们添加到列表中并使用 Distinct
LINQ 函数获得唯一的匹配项,并使用 OrderBy
从最长到最短的顺序对它们进行排序LINQ 函数。然后循环遍历生成的 RouteMap 并替换原始字符串。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var input = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
Console.WriteLine(input);
var re = new Regex(@"\|.*?\|");
var matches = re.Matches(input);
var mz = new List<string>();
foreach(Match m in matches)
{
mz.Add(m.Groups[0].ToString());
}
var routeMap = mz.Distinct().OrderByDescending(n => n.Length).ToList(); //Get distinct, and sort it longest to shortest... need it this way or it won't do the replacement correctly.
for (var i = 0; i < routeMap.Count; i++)
{
input = input.Replace(routeMap[i], string.Format("~{0}~", i));
}
Console.WriteLine(input);
Console.WriteLine();
Console.WriteLine("The route map replacement key:");
var idx = 0;
routeMap.ForEach(m => Console.WriteLine("{0}: {1}", idx++, m));
}
}
运行 样本位于:https://dotnetfiddle.net/PIuuae
我想出了一个建议来获得你的第二个输出选项。
您可以使用 MatchEvaluator
将匹配传递给单独的方法,并在该方法中增加一个 "global" 计数器:
public string ReplaceMatch(Match m)
{
i++;
return "~" + i.ToString() + "~";
}
public static int i = -1;
// ... then, in your calling method
var txt = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var fields = Regex.Matches(txt, @"\|.*?\|");
var txt2 = Regex.Replace(txt, @"\|.*?\|", new MatchEvaluator(ReplaceMatch));
输出:
iif(instr(~0~,~1~)>0,~2~,~3~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~8~)>0,~9~,~10~ & ~11~ & ~12~) & iif(~13~=~14~,~15~,~16~ & ~17~)
与这些占位符对应的匹配值保存在 fields
变量中,因此稍后您将能够匹配它们。
编辑:对于选项 1(这是您编辑问题后的唯一选项),答案是创建一个包含不同项目的字典,并在替换中使用它方法:
var txt = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var fields = Regex.Matches(txt, @"\|.*?\|").Cast<Match>().Select(p=> p.Value).Distinct().Select((s, i) => new { s, i }).ToDictionary(x => x.s, x => x.i);
var txt3 = Regex.Replace(txt, @"\|.*?\|", m => string.Format("~{0}~", fields[m.Value]));
输出:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~2~ & ~3~) & ~4~ & iif(instr(~5~,~1~)>0,~5~,~5~ & ~2~ & ~6~) & iif(~5~=~7~,~7~,~8~ & ~5~)
我会使用一些 lambda 函数:
// This one gets the index from the list of matches
private static string LookupReplace(string text, List<string> newList)
{
var result = "~" + newList.IndexOf(text).ToString() + "~";
return result;
}
// This one just increments a global counter
private static string NumberedReplace()
{
i++;
return "~" + i.ToString() + "~";
}
public static int i = -1;
public static void Main()
{
string text = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var re = new Regex(@"\|.*?\|");
var newList = re.Matches(text)
.OfType<Match>()
.Select(m => m.Value)
.ToList();
// First replace with index
string result = re.Replace(text, x => LookupReplace(x.Value, newList));
Console.WriteLine(result);
// Second replace with counter
result = re.Replace(text, x => NumberedReplace());
Console.WriteLine(result);
}
每次替换的输出:
iif(instr(~0~,~1~)>0,~0~,~0~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~1~)>0,~7~,~7~ & ~4~ & ~12~) & iif(~7~=~14~,~14~,~16~ & ~7~)
iif(instr(~0~,~1~)>0,~2~,~3~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~8~)>0,~9~,~10~ & ~11~ & ~12~) & iif(~13~=~14~,~15~,~16~ & ~17~)