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次字符串替换,其中每次替换都会修改下一次替换要使用的文本(

还是这是它能做到的最好的方式?

谢谢。

C#Regex,任何更有效的解析由符号包围的字符串的方法

我认为这是对这个问题的独特看法。您可以构建一个类,该类将用于逐个构建整个模式。这个类将负责生成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将其自身的GroupNameMatch的捕获组进行比较。如果组名被捕获,那么我们有一个命中,并且我们返回这个替换器的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方法即可。

请记住,这种方法更多地针对所描述的问题。它可能适用于更一般的场景,但我只处理过您所介绍的内容。此外,由于这更多的是一个解析问题,解析器可能是正确的途径——尽管学习曲线会更高。

还要记住,我还没有对这段代码进行分析。它当然不会多次在目标字符串上循环,但在替换过程中会涉及额外的方法调用。您肯定希望在您的环境中进行测试。