【问题标题】:Remove text in-between delimiters in a string (using a regex?)删除字符串中分隔符之间的文本(使用正则表达式?)
【发布时间】:2010-11-24 11:16:49
【问题描述】:

考虑找到一对匹配的字符集的要求,并删除它们之间的任何字符,以及那些字符/分隔符。

以下是分隔符集:

 []    square brackets
 ()    parentheses
 ""    double quotes
 ''    single quotes

以下是一些应该匹配的字符串示例:

 Given:                       Results In:
-------------------------------------------
 Hello "some" World           Hello World
 Give [Me Some] Purple        Give Purple
 Have Fifteen (Lunch Today)   Have Fifteen
 Have 'a good'day             Have day

还有一些不应该匹配的字符串示例:

 Does Not Match:
------------------
 Hello "world
 Brown]co[w
 Cheese'factory

如果给定的字符串不包含匹配的分隔符集,则不会对其进行修改。输入字符串可能有许多匹配的分隔符对。如果一组 2 个分隔符重叠(即he[llo "worl]d"),那将是我们可以在这里忽略的边缘情况。

算法看起来像这样:

string myInput = "Give [Me Some] Purple (And More) Elephants";
string pattern; //some pattern
string output = Regex.Replace(myInput, pattern, string.Empty);

问题:您将如何使用 C# 实现这一目标?我倾向于使用正则表达式。

奖励:有没有简单的方法来匹配常量或某种列表中的开始和结束分隔符?我正在寻找的解决方案很容易更改分隔符,以防业务分析师提出新的分隔符集。

【问题讨论】:

    标签: c# .net regex algorithm string


    【解决方案1】:

    简单的正则表达式是:

    string input = "Give [Me Some] Purple (And More) Elephants";
    string regex = "(\\[.*\\])|(\".*\")|('.*')|(\\(.*\\))";
    string output = Regex.Replace(input, regex, "");
    

    至于您想要构建正则表达式的自定义方式,您只需要构建部分:

    ('.*')  // example of the single quote check
    

    然后将每个单独的正则表达式部分与一个 OR(正则表达式中的 |)连接起来,就像我原来的例子一样。构建正则表达式字符串后,只需运行一次。关键是将正则表达式进行一次检查,因为对一个项目执行许多正则表达式匹配,然后遍历许多项目可能会导致性能显着下降。

    在我的第一个示例中,它将代替以下行:

    string input = "Give [Me Some] Purple (And More) Elephants";
    string regex = "Your built up regex here";
    string sOutput = Regex.Replace(input, regex, "");
    

    我相信有人会发布一个很酷的 linq 表达式来构建基于要匹配的分隔符对象数组的正则表达式。

    【讨论】:

    • 这现在(最有可能)按照“给[我一些]紫色(和更多)[大]大象”的预期工作。这可以通过使用 '.*?' 来解决而不是上面提供的表达式中的 '.*'。
    【解决方案2】:

    一个简单的方法是这样做:

    string RemoveBetween(string s, char begin, char end)
    {
        Regex regex = new Regex(string.Format("\\{0}.*?\\{1}", begin, end));
        return regex.Replace(s, string.Empty);
    }
    
    string s = "Give [Me Some] Purple (And More) \\Elephants/ and .hats^";
    s = RemoveBetween(s, '(', ')');
    s = RemoveBetween(s, '[', ']');
    s = RemoveBetween(s, '\\', '/');
    s = RemoveBetween(s, '.', '^');
    

    把return语句改成下面这样可以避免出现重复的空格:

    return new Regex(" +").Replace(regex.Replace(s, string.Empty), " ");
    

    最终的结果是:

    "Give Purple and "
    

    Disclamer:单个正则表达式可能会比这更快。

    【讨论】:

    • OP 没有提到“和帽子”。 “给我紫色和更多的大象”是 OP 明确要求的。你为什么歪曲他的话并在等式中加上帽子?
    • +1。发现自己回到了这个线程,并没有意识到我已经发布了上述评论!幽默的尝试很差。谢谢你的回答。
    • 为什么要戴帽子?!我想这是我自己在幽默方面的拙劣尝试;)。很高兴看到这仍然有用。
    • 我喜欢这种方法,但是如果你有多个中间层,它就不起作用了,像这样:“[[One string] another string]”变成“ another string]”
    【解决方案3】:

    我要补充一句老话,“你有问题,你想使用正则表达式。现在你有两个问题。”

    我想出了一个快速的正则表达式,希望能帮助你找到你想要的方向:

    [.]*(\(|\[|\"|').*(\]|\)|\"|')[.]*
    

    圆括号、方括号、双引号被转义,而单引号可以单独保留。

    为了将上述表达式转换为英文,我允许在匹配分隔符之间匹配表达式之前和之后的任意数量的字符。

    开放的分隔符短语是(\(|\[|\"|') 这有一个匹配的结束短语。为了在将来使其更具可扩展性,您可以删除实际的分隔符并将它们包含在配置文件、数据库或您可能选择的任何位置中。

    【讨论】:

    • +1 正则表达式似乎可以满足他的需要。只需一个简单的 regex.Replace 即可完成。
    • 为“......现在你有两个问题。”,大声笑
    【解决方案4】:

    Bryan Menard's regular expression 的基础上,我做了一个扩展方法,它也适用于嵌套替换,例如“[Test 1 [[Test2] Test3]] Hello World”:

        /// <summary>
        /// Method used to remove the characters betweeen certain letters in a string. 
        /// </summary>
        /// <param name="rawString"></param>
        /// <param name="enter"></param>
        /// <param name="exit"></param>
        /// <returns></returns>
        public static string RemoveFragmentsBetween(this string rawString, char enter, char exit) 
        {
            if (rawString.Contains(enter) && rawString.Contains(exit))
            {
                int substringStartIndex = rawString.IndexOf(enter) + 1;
                int substringLength = rawString.LastIndexOf(exit) - substringStartIndex;
    
                if (substringLength > 0 && substringStartIndex > 0)
                {
                    string substring = rawString.Substring(substringStartIndex, substringLength).RemoveFragmentsBetween(enter, exit);
                    if (substring.Length != substringLength) // This would mean that letters have been removed
                    {
                        rawString = rawString.Remove(substringStartIndex, substringLength).Insert(substringStartIndex, substring).Trim();
                    }
                }
    
                //Source: https://stackoverflow.com/a/1359521/3407324
                Regex regex = new Regex(String.Format("\\{0}.*?\\{1}", enter, exit));
                return new Regex(" +").Replace(regex.Replace(rawString, string.Empty), " ").Trim(); // Removing duplicate and tailing/leading spaces
            }
            else
            {
                return rawString;
            }
        }
    

    在建议的情况下,此方法的用法如下所示:

    string testString = "[Test 1 [[Test2] Test3]] Hello World";
    testString.RemoveFragmentsBetween('[',']');
    

    返回字符串“Hello World”。

    【讨论】:

    • 当我将此方法放入页面时,我收到一条警告,指出字符串不包含 RemoveFragmentsBetween 的定义。
    • 我猜你已经把它放在一个未包含的命名空间中。尝试谷歌搜索“字符串不包含扩展 C# 的定义”
    • 这不是 100%。 "[Test 1] [Test 2 [Test3]] Hello World".RemoveFragmentsBetween('[', ']') 返回 "] Hello World"。
    • 以下解决方案似乎对嵌套括号更健壮:stackoverflow.com/a/14407908/86047
    【解决方案5】:

    使用下面的正则表达式

    (\{\S*\})
    

    这个正则表达式的作用是将任何出现的 {word} 替换为您要替换的 modifiedWord。

    一些示例 c# 代码:

     static readonly Regex re = new Regex(@"(\{\S*\})", RegexOptions.Compiled);
            /// <summary>
            /// Pass text and collection of key/value pairs. The text placeholders will be substituted with the collection values.
            /// </summary>
            /// <param name="text">Text that containes placeholders such as {fullname}</param>
            /// <param name="fields">a collection of key values pairs. Pass <code>fullname</code> and the value <code>Sarah</code>. 
            /// DO NOT PASS keys with curly brackets <code>{}</code> in the collection.</param>
            /// <returns>Substituted Text</returns>
            public static string ReplaceMatch(this string text, StringDictionary fields)
            {
                return re.Replace(text, match => fields[match.Groups[1].Value]);
            }
    

    在诸如

    这样的句子中

    Regex Hero 是一个实时的 {Silverlight} 正则表达式 测试员。

    它将仅替换 {Silverlight} 而不是从第一个 { 括号开始到最后一个 } 括号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多