【问题标题】:optimal way to escape character转义字符的最佳方法
【发布时间】:2011-12-02 13:01:43
【问题描述】:

我需要转义这些字符:+-&|!(){}[]^"~*?:\,方法是在它们前面加上 \\。 做这个的最好方式是什么。我的第一个想法是使用替换,但这会搜索每个要替换的项目的字符串。 我在想一定有一种方法可以使用正则表达式来一次性完成。

【问题讨论】:

标签: c# string escaping replace


【解决方案1】:

最好的方法就是使用正则表达式(Regex)!

string str = @"+-&|!(){}[]^""~*?:\";
string pattern = @"(\+|\-|\&|\||\!|\(|\)|\{|\}|\[|\]|\^|\""|\~|\*|\?|\:|\\)";
string output = Regex.Replace(str, pattern, @"\$1");

给出以下输出:

\+\-\&\|\!\(\)\{\}\[\]\^\"\~\*\?\:\\

【讨论】:

  • 为什么?正则表达式很方便,但速度可能很慢。事实上,.NET 4.5 中为数不多的特色改进之一就是限制正则表达式的执行时间。 en.wikipedia.org/wiki/…
【解决方案2】:

使用 StringBuilder 可能是比正则表达式更好的选择。这是一个支持这个想法的 msdn 帖子:Regex.Replace vs String.Replace vs StringBuilder.Replace

public const string CharsToBeEscaped = "+-&|!(){}[]^\"~*?:\\'";

string s = "+-&|!(){}[]^\"~*?:\\";

StringBuilder sb = new StringBuilder();
sb.Append( s );

for ( int i = 0; i < CharsToBeEscaped.Length; i++ ) {
    sb.Replace( CharsToBeEscaped.Substring(i,1), @"\" + CharsToBeEscaped[i] );
}
sb.Replace( @"\\", @"\" );

s = sb.ToString();

【讨论】:

  • +½ 用于建议 StringBuilder。但是,看过您的文章后,我认为它展示了与我的答案中的代码略有不同的方法。我认为它没有那么有效,但不确定。我也认为这篇文章很难阅读。您可以发布您将使用的代码吗?无论如何,我赞成您对另一个问题的答案之一。 :)
  • @MarkByers 这将是我的实现。
  • +1 用于提供代码。与我的代码相比,我仍然有点担心性能......我没有测试过它,但我怀疑这会因为反复更换而变慢。还有一个错误,因为它首先用反斜杠转义特殊字符,然后用另一个反斜杠转义 那些 反斜杠,我认为这不是他想要的。
  • 修复了双斜线问题,但无论哪种方式,我认为你对性能的看法是正确的,你的会拿走蛋糕。看到 LINQ 也总是很高兴,因为我还没有非常熟悉它。无论如何,编写这段代码是一个好习惯;)
【解决方案3】:

免责声明:请阅读其他答案中关于 not 使用正则表达式的参数,如果这会导致您的应用程序出现性能问题(例如,如果这是一个非常大的字符串,其中包含很多您的实例可转义字符)。但是,如果您选择正则表达式,下面将解释如何在 1 行代码中执行此操作。

您正在寻找的是Regex.Replace。你提供一个你正在搜索的正则表达式、输入和一个MatchEvaluator,它为每个匹配运行。在您的情况下,您只需返回 String.Concat(@"\",match.Value)

类似这样的东西(input 是你的字符串):

var replaced = Regex.Replace(input, //your string
         @"[\+\-&|!]", // partial regex to give you an idea
         match => String.Concat(@"\",match.Value)); //MatchEvaluator, runs for each capture

【讨论】:

    【解决方案4】:

    可以使用正则表达式。最棘手的部分是正确转义特殊字符而不进入反斜杠地狱:

    s = Regex.Replace(s, @"[+\-&|!(){}[\]^""~*?:\\]", "\\$0");
    

    StringBuilder 解决方案mentioned by Eric J. 简单而优雅。这是一种编码方式:

    StringBuilder sb = new StringBuilder();
    foreach (char c in s)
    {
        if ("+-&|!(){}[]^\"~*?:\\".Contains(c))
        {
            sb.Append('\\');
        }
        sb.Append(c);
    }
    s = sb.ToString();
    

    【讨论】:

    • 如果字符串很大,请使用 StringBuilder 构造函数,该构造函数允许您提供初始大小并将其设置为略大于原始字符串。
    【解决方案5】:

    字符串在 C# 中是不可变的,这意味着每个 string.Replace() 都会创建原始字符串的新修改副本。

    对于许多真正无关紧要的应用程序。不过,既然你在问这个问题,我认为它可能是你的情况。

    最有效的方法可能是使用 StringBuilder 来构建修改后的字符串。循环遍历源字符串一次,然后在每个字符串位置附加字符,或者在适用的情况下附加转义版本。使用 StringBuilder constructor 预分配初始内部缓冲区大小,使其略大于源字符串。

    RegEx,大多数其他答案都提到,对于这个特定的应用程序可能也非常有效,并且涉及的代码更少。但是,由于 RegEx 必须固有地应用通用解析逻辑,因此它不能像针对您的特定需求调整的解决方案那样快。此外,在某些情况下(可能不是这个)RegEx 可能非常慢。见

    http://en.wikipedia.org/wiki/.NET_Framework_version_history#Common_Language_Runtime_.28CLR.29

    http://www.codinghorror.com/blog/2006/01/regex-performance.html

    【讨论】:

    • 小问题。您对 StringBuilder 容量的描述不太准确。在 .NET 3.5 及更早版本中,容量始终为 2^n。所以它介于完全等于源字符串和几乎是源字符串的两倍之间。在 4.0 中,容量与源字符串相同。 (对于两个最小容量 = 16)。
    猜你喜欢
    • 1970-01-01
    • 2010-10-12
    • 2012-01-28
    • 1970-01-01
    • 2011-01-18
    • 2021-03-11
    • 2014-06-21
    • 1970-01-01
    • 2010-10-10
    相关资源
    最近更新 更多