C# 使用正则表达式进行字符串操作

C# 使用正则表达式进行字符串操作,c#,regex,C#,Regex,考虑到下面的场景,我想知道是否可以用我还不太熟悉的正则表达式编写更好的解决方案。我在基本的c#字符串操作中发现了漏洞,尽管它在某种程度上是有效的。非常感谢您的想法和想法 多谢各位 克雷格 给定下面的字符串“story”,编写脚本以执行以下操作: 变量文本由{}括起 如果变量文本为空,请删除[]中包含的任何其他文本 要删除的文本可以用[]深嵌套 格式: XYZ Company [- Phone: [({404}) ]{321-4321} [Ext: {6789}]] 示例: 填写所有变量

考虑到下面的场景,我想知道是否可以用我还不太熟悉的正则表达式编写更好的解决方案。我在基本的c#字符串操作中发现了漏洞,尽管它在某种程度上是有效的。非常感谢您的想法和想法

多谢各位

克雷格

给定下面的字符串“story”,编写脚本以执行以下操作:

  • 变量文本由
    {}
    括起
  • 如果变量文本为空,请删除
    []
    中包含的任何其他文本
  • 要删除的文本可以用
    []
    深嵌套
  • 格式:

        XYZ Company [- Phone: [({404}) ]{321-4321} [Ext: {6789}]]
    
    示例:

  • 填写所有变量文本

    XYZ Company - Phone: (404) 321-4321 Ext: 6789
    
  • 未输入分机,请删除“分机:”

  • 没有输入分机和区号,请删除“分机:”和“()”

  • 没有分机,没有电话号码,也没有区号,请删除“分机:”和“()”以及“-phone:”

  • 下面是我的简单字符串操作解决方案

    private string StoryManipulation(string theStory)
        {
            // Loop through story while there are still curly brackets
            while (theStory.IndexOf("{") > 0)
            {
                // Extract the first curly text area
                string lcCurlyText = StringUtils.ExtractString(theStory, "{", "}");                
    
                // Look for surrounding brackets and blank all text between
                if (String.IsNullOrWhiteSpace(lcCurlyText))
                {
                    for (int lnCounter = theStory.IndexOf("{"); lnCounter >= 0; lnCounter--)
                    {
                        if (theStory.Substring(lnCounter - 1, 1) == "[")
                        {
                            string lcSquareText = StringUtils.ExtractString(theStory.Substring(lnCounter - 1), "[", "]");
                            theStory = StringUtils.ReplaceString(theStory, ("[" + lcSquareText + "]"), "", false);
                            break;
                        }
                    }
                }
                else
                {
                    // Replace current curly brackets surrounding the text
                    theStory = StringUtils.ReplaceString(theStory, ("{" + lcCurlyText + "}"), lcCurlyText, false);
                }
            }
            // Replace all brackets with blank (-1 all instances)
            theStory = StringUtils.ReplaceStringInstance(theStory, "[", "", -1, false);
            theStory = StringUtils.ReplaceStringInstance(theStory, "]", "", -1, false);
            return theStory.Trim();
        }
    

    处理嵌套结构通常超出正则表达式的范围。但是我认为有一个解决方案,如果你在一个循环中运行regex替换,从内到外开始。不过,您需要一个回调函数(一个
    MatchEvaluator
    ):

    然后可以创建评估器:

    MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback);
    
    然后您可以在循环中调用它,直到替换不再改变任何内容:

    newString = Regex.Replace(
        oldString,
        @"
        \[    # a literal [
        (     # start a capturing group. this is what we access with "match.Groups[1]"
            [^{}[\]]
              # a negated character class, that matches anything except {, }, [ and ]
            * # arbitrarily many of those
        )     # end of the capturing group
        \{    # a literal {
        ([^{}[\]]*)
              # the same thing as before, we will access this with "match.Groups[2]"
        }     # a literal }
        ([^{}[\]]*)
              # "match.Groups[3]"
        ]     # a literal ]
        ",
        evaluator,
        RegexOptions.IgnorePatternWhitespace
    );
    
    以下是正则表达式的无空格版本:

    \[([^{}[\]]*)\{([^{}[\]]*)}([^{}[\]]*)]
    

    我说得对吗。。。搜索
    {…}
    如果它是空的或只包含空格,则要删除包含匹配的
    {…}
    的“父级”
    […]
    ?此外,如果输入了区号和分机号码,但省略了主电话号码,那么我想您仍然希望删除所有内容?是的,这是正确的。任何文本都是在[…]之外的,都是单独留下的。哇,那太快了,我想这就是我要找的!完美的非常感谢您的解释。虽然结束文字括号/大括号不需要转义(您也没有),但为了清晰起见,最好还是继续转义它们(IMHO)。文本是廉价的,可读性应该始终是头等大事。另外,为什么不在自由间距模式下编写一次正则表达式,并内置注释,以开始并完成它->自我文档!。再一次,很好的解释+1@ridgerunner看,我把转义放在可能的地方,完全是因为可读性:D。我想这是一个品味的问题。自由空间的事情。。。是的,这是我需要习惯这些答案的东西(当我自己使用或编写正则表达式时,我更喜欢它们是一行程序,因为我通常能比阅读长解释更快地理解它们的意思)是的-不需要评论短解释。但对于任何非琐碎的事情,评论都是必不可少的。在编写汇编语言多年后,我养成了评论每一条指令的习惯(regex也是低级的)。但评论也有一种艺术——不需要陈述显而易见的东西,而且必须保持简洁。显示了我为复杂正则表达式开发的注释样式。缩进可以直观地看到深嵌套结构(YMMV)的括号匹配和备选方案。干杯
    string ReplaceCallback(Match match)
    {
        if(String.IsNullOrWhiteSpace(match.Groups[2])
            return "";
        else
            return match.Groups[1]+match.Groups[2]+match.Groups[3];
    }
    
    MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback);
    
    newString = Regex.Replace(
        oldString,
        @"
        \[    # a literal [
        (     # start a capturing group. this is what we access with "match.Groups[1]"
            [^{}[\]]
              # a negated character class, that matches anything except {, }, [ and ]
            * # arbitrarily many of those
        )     # end of the capturing group
        \{    # a literal {
        ([^{}[\]]*)
              # the same thing as before, we will access this with "match.Groups[2]"
        }     # a literal }
        ([^{}[\]]*)
              # "match.Groups[3]"
        ]     # a literal ]
        ",
        evaluator,
        RegexOptions.IgnorePatternWhitespace
    );
    
    \[([^{}[\]]*)\{([^{}[\]]*)}([^{}[\]]*)]