我不确定是否可以问......但是这里有。
我实现了一个使用正则表达式解析字符串的方法,每个匹配都通过带有顺序的委托进行解析(实际上,顺序并不重要 - 我想,等等,是吗?......但我这样写了,它没有经过全面测试):
@"(?<!\\)\$.+?\$"
then String.Replace:@"\$", @"$"
;替换美元符号包围的字符串。忽略反斜杠,然后删除反斜杠。例如:&#34; $全球名称$&#34; - &GT; &#34; motherofglobalvar&#34;,&#34; Money \ $ 9000&#34; - &GT; &#34;金钱$ 9000&#34; @"(?<!\\)%.+?%"
then String.Replace @"\%", @"%"
;替换百分号包围的字符串。忽略反斜杠,然后删除反斜杠。与前面的示例相同:&#34;%local var%&#34; - &GT; &#34; lordoflocalvar&#34;,&#34;超过9000 \%&#34; - &GT; &#34;超过9000%&#34; @"(?<!\\)@"
then String.Replace @"\@", @"@"
;替换char&#39; @&#39;用空格,&#39; &#39 ;.但忽略反斜杠,然后删除反斜杠。例如:&#34;我@ @ @ @ @ @ @ @&#34; - &GT; &#34;我太过努力了#34;,&#34; qw \ @ op&#34; - &GT; &#34; QW @ OP&#34; 在没有太多经验的情况下我做了什么(我认为):
//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次regex.replace,3次string.replace,其中每次替换修改下一次替换时使用的文本)
或者它是最好的方式吗?
感谢。
答案 0 :(得分:0)
我认为,这是对问题的独特看法。您可以构建一个用于逐个构建整体模式的类。此类将负责生成将MatchEvaluator
传递给Replace
的{{1}}代理。
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
}
};
}
}
Pattern
和Replacement
代表什么应该是显而易见的。 GroupName
是一种让替换评估者知道哪个RegexReplacer
片段导致匹配的黑客攻击。 NextReplacer
指向另一个包含不同模式片段的替换器实例(等)。
这里的想法是拥有一种代表整体模式的对象链接列表。您可以在最外层的替换器上调用GetAggregatedPattern
以获得完整的模式 - 每个替换器调用下一个替换器GetAggregatedPattern
来获取替换器的模式片段,连接自己的片段。 GetReplacementDelegate
生成MatchEvaluator
。此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);
因为您希望每个替换者知道它是否受到攻击,并且因为我们通过使用组名来攻击它,所以您希望确保每个组名都是不同的。确保这一点的一种简单方法是使用与变量名称相同的名称,因为在同一范围内不能有两个同名的变量。
你可以看到我正在单独构建模式的每个部分,但是在构建时,我将前一个替换器作为第4个参数传递给当前的替换器。这构建了替代品链。构建之后,我使用构造的最后一个替换器来生成整体模式和评估器。如果你使用任何东西,那么你将只有整体模式的一部分。最后,它只是将生成的模式和求值程序传递给Replace
方法。
请记住,此方法更多地针对所述问题。它可能适用于更一般的场景,但我只能使用您所呈现的内容。此外,由于这更像是一个解析问题,解析器可能是正确的路径 - 虽然学习曲线会更高。
另请注意,我还没有对此代码进行分析。它当然不会多次遍历目标字符串,但它确实涉及替换期间的其他方法调用。你当然希望在你的环境中测试它。