C#Regex,任何更有效的解析由符号包围的字符串的方法
本文关键字:符号 包围 字符串 方法 任何更 有效 C#Regex | 更新日期: 2023-09-27 18:10:27
我不确定是否可以询问。。。但事情是这样的。
我实现了一个使用regex解析字符串的方法,每个匹配项都通过带有顺序的委托进行解析(实际上,顺序并不重要——我想,等等,是吗?…但我是这样写的,它还没有经过充分测试(:
- 图案规则。替换:先
@"(?<!'')'$.+?'$"
,然后字符串。替换:@"'$", @"$"
;替换用美元符号括起来的字符串。忽略反斜杠,然后删除反斜杠。例如:"$global-name$"->"motherofglobalvar","Money''$9000"->"Money$9000"> - 图案规则。先替换
@"(?<!'')%.+?%"
,然后替换字符串。更换@"'%", @"%"
;替换用百分号括起来的字符串。忽略反斜杠,然后删除反斜杠。与前面的示例相同:"%local var%"->"lordoflocalvar","它超过9000''%"->"它超过9000%"> - 图案规则。先替换
@"(?<!'')@"
,然后替换字符串。更换@"'@", @"@"
;将字符"@"替换为空白"。但是忽略反斜杠,然后删除反斜杠。例如:"我@hit@the@ground@too@hard"->"我落地太用力了","qw''@op"->"qw@op">
我在没有太多经验的情况下所做的(我认为(:
//parse variable
public static string ParseVariable(string text)
{
return Regex.Replace(Regex.Replace(Regex.Replace(text, @"(?<!'')'$.+?'$", match =>
{
string trim = match.Value.Trim('$');
string trimUpper = trim.ToUpper();
return variableGlobal.ContainsKey(trim) ? variableGlobal[trim] : match.Value;
}).Replace(@"'$", @"$"), @"(?<!'')%.+?%", match =>
{
string trim = match.Value.Trim('%');
string trimUpper = trim.ToUpper();
return variableLocal.ContainsKey(trim) ? variableLocal[trim] : match.Value;
}).Replace(@"'%", @"%"), @"(?<!'')@", " ").Replace(@"'@", @"@");
}
简而言之,我使用的是:Regex.Replace().Replace()
由于我需要解析3种符号,我将其链接如下:Regex.Replace(Regex.Replace(Regex.Replace().Replace()).Replace()).Replace()
还有比这更有效的方法吗?我的意思是,就像不需要看文本6次?(3次正则表达式替换,3次字符串替换,其中每次替换都会修改下一次替换要使用的文本(
还是这是它能做到的最好的方式?
谢谢。
我认为这是对这个问题的独特看法。您可以构建一个类,该类将用于逐个构建整个模式。这个类将负责生成MatchEvaluator
委托,该委托也将传递给Replace
。
class RegexReplacer
{
public string Pattern { get; private set; }
public string Replacement { get; private set; }
public string GroupName { get; private set; }
public RegexReplacer NextReplacer { get; private set; }
public RegexReplacer(string pattern, string replacement, string groupName, RegexReplacer nextReplacer = null)
{
this.Pattern = pattern;
this.Replacement = replacement;
this.GroupName = groupName;
this.NextReplacer = nextReplacer;
}
public string GetAggregatedPattern()
{
string constructedPattern = this.Pattern;
string alternation = (this.NextReplacer == null ? string.Empty : "|" + this.NextReplacer.GetAggregatedPattern()); // If there isn't another replacer, then we won't have an alternation; otherwise, we build an alternation between this pattern and the next replacer's "full" pattern
constructedPattern = string.Format("(?<{0}>{1}){2}", this.GroupName, this.Pattern, alternation); // The (?<XXX>) syntax builds a named capture group. This is used by our GetReplacementDelegate metho.
return constructedPattern;
}
public MatchEvaluator GetReplaceDelegate()
{
return (match) =>
{
if (match.Groups[this.GroupName] != null && match.Groups[this.GroupName].Length > 0) // Did we get a hit on the group name?
{
return this.Replacement;
}
else if (this.NextReplacer != null) // No? Then is there another replacer to inspect?
{
MatchEvaluator next = this.NextReplacer.GetReplaceDelegate();
return next(match);
}
else
{
return match.Value; // No? Then simply return the value
}
};
}
}
CCD_ 11和CCD_。CCD_ 13是一种让替换评估器知道哪个CCD_。NextReplacer
指向另一个包含不同模式片段的替换实例(等人(
这里的想法是有一种对象的链接列表,它将代表整个模式。您可以在最外层的替换器上调用GetAggregatedPattern
来获得完整的模式——每个替换器调用下一个替换器的GetAggregatedPattern
来获得该替换器的模式片段,它将自己的片段连接到该片段。CCD_ 18生成CCD_。该MatchEvaluator
将其自身的GroupName
与Match
的捕获组进行比较。如果组名被捕获,那么我们有一个命中,并且我们返回这个替换器的Replacement
值。否则,我们将进入下一个替换器(如果有(,并重复组名比较。如果任何替换品都没有命中,那么我们只需返回原始值(即模式匹配的值;这种情况应该很少见(。
这样的用法可能看起来像这样:
string target = @"$global name$ Money '$9000 %local var% It's over 9000'% I@hit@the@ground@too@hard qw'@op";
RegexReplacer dollarWrapped = new RegexReplacer(@"(?<!'')'$[^$]+'$", "motherofglobalvar", "dollarWrapped");
RegexReplacer slashDollar = new RegexReplacer(@"'''$", string.Empty, "slashDollar", dollarWrapped);
RegexReplacer percentWrapped = new RegexReplacer(@"(?<!'')%[^%]+%", "lordoflocalvar", "percentWrapped", slashDollar);
RegexReplacer slashPercent = new RegexReplacer(@"''%", string.Empty, "slashPercent", percentWrapped);
RegexReplacer singleAt = new RegexReplacer(@"(?<!'')@", " ", "singleAt", slashPercent);
RegexReplacer slashAt = new RegexReplacer(@"''@", "@", "slashAt", singleAt);
RegexReplacer replacer = slashAt;
string pattern = replacer.GetAggregatedPattern();
MatchEvaluator evaluator = replacer.GetReplaceDelegate();
string result = Regex.Replace(target, pattern, evaluator);
因为你想让每个替换者知道它是否被击中,而且因为我们是通过使用组名来破解的,所以你想确保每个组名都是不同的。确保这一点的一个简单方法是使用与变量名称相同的名称,因为在同一范围内不能有两个名称相同的变量。
您可以在上面看到,我正在单独构建模式的每个部分,但在构建时,我将上一个替换器作为第四个参数传递给当前替换器。这就建立了一个替代品链。构建完成后,我使用构建的最后一个替换器来生成整个模式和评估器。如果你使用了除之外的任何东西,那么你将只拥有整体模式的一部分。最后,只需将生成的模式和评估器传递给Replace
方法即可。
请记住,这种方法更多地针对所描述的问题。它可能适用于更一般的场景,但我只处理过您所介绍的内容。此外,由于这更多的是一个解析问题,解析器可能是正确的途径——尽管学习曲线会更高。
还要记住,我还没有对这段代码进行分析。它当然不会多次在目标字符串上循环,但在替换过程中会涉及额外的方法调用。您肯定希望在您的环境中进行测试。