用其他坏字符替换字符串中的坏字符

8

我想知道替换一串需要依次替换的字符串中最简单的方法。

例如:

var str = "[Hello World]";
//enclose all occurences of [ and ] with brackets[] 
str = str.Replace("[","[[]").Replace("]","[]]");
  • 期望结果:[[]Hello World[]]
  • 实际结果:[[[]]Hello World[]]

显然原因是在已修改的字符串上执行了第二次替换。

那么如何将所有“坏”字符替换为包含“坏”字符的字符?


对所有方法进行快速测量后,StringBuilder 是最有效的方法。

190kb 文件(全部毫秒)

  regexTime           40.5065  
  replaceTime         20.8891  
  stringBuilderTime    6.9776

7MB文件

  regexTime           1209.3529           
  replaceTime          403.3985   
  stringBuilderTime    175.2583
顺便提一下,直接使用StringBuilder方法比John的方法要快两倍,而SeheAggregate方法则较慢。我已将其制作成扩展程序:
public static String EncloseChars(this string input, char[] charsToEnclose, String leftSide, String rightSide) {
    if (charsToEnclose == null || leftSide == null || rightSide == null)
        throw new ArgumentException("Invalid arguments for EncloseChars", charsToEnclose == null ? "charsToEnclose" : leftSide == null ? "leftSide" : "rightSide");
    Array.Sort(charsToEnclose);
    StringBuilder sb = new StringBuilder();
    foreach (char c in input) {
        if (Array.BinarySearch(charsToEnclose, c) > -1)
            sb.Append(leftSide).Append(c).Append(rightSide);
        else 
            sb.Append(c);
    }
    return sb.ToString();
}

"[Hello World]".EncloseChars(new char[]{'[', ']'},"[","]");
6个回答

5

这里有一种非常不酷的方法来实现它。但我认为它有一个相当接近于万无一失的优点,而且不使用正则表达式(如果您不想使用正则表达式)。

StringBuilder sb = new StringBuilder();
foreach (char c in str.ToCharArray()) {
    if (c == '[' || c == ']') {
        sb.Append('[' + c + ']');
    }
    else {
        sb.Append(c);
    }
}
string result = sb.ToString();

谢谢。通常最好/最快的方法并不酷。但是如果隐藏在扩展方法中,就没有问题了 ;) - Tim Schmelter

4

如何处理:

str = str.Replace("[", "$1[$2")
         .Replace("]", "$1]$2")
         .Replace("$1", "[")
         .Replace("$2", "]");

2
不错的想法,使用监视器值作为中介。 - Oded
4
你需要检查一下字符串是否已经包含了这些监控值,否则同样的问题会再次发生。例如:你好 [$1] - Oliver
将编辑以替换监视器值+实际字符的方式在替换实际字符值之前可能会解决奥利弗的问题(虽然是一种墙和梯子的方式),但我认为这样做会牺牲可读性。 - John M Gant

3
这种优雅的正则表达式方法怎么样:
Regex.Replace("[Hello World]", @"[\[\]]", "[$0]");

进行单元测试吗?

[TestMethod]
public void UnitTestThat()
{
    Assert.AreEqual(@"[[]Hello World[]]", Regex.Replace("[Hello World]", @"[\[\]]", "[$0]"));
}

测试通过


编辑@JohnMcGrant

这是比你的代码稍微不那么低效的版本,其行为与上面的正则表达式完全相同:

string result = input.Aggregate(new StringBuilder(), (a, c) =>
    -1 != "[]".IndexOf(c) ? a.AppendFormat("[{0}]", c) : a.Append(c)).ToString();

可以大胆猜测这种情况不会发生,但是如果方括号中的文本可能包含方括号,而且以某种方式进行了转义,那么正则表达式会出现错误吗? - John M Gant
@JohnMGant:不会,因为这意味着需求发生了变化。如果问题不同了呢?那么答案就会失效吗?不会的。 - sehe
添加了基于@JohnMGant版本的替代方法。我认为正则表达式仍然是最好的方法 :) - sehe

1
怎么样:
char[] replacedChars = str.SelectMany(ch => 
                                     (ch == '[' ? new char[] {'[', '[', ']'} :
                                     (ch == ']' ? new char[] {'[', ']', ']'} : 
                                     new char[] {ch}))).ToArray();
string replaced = new string(replacedChars);

请注意,这样可以避免多重循环的问题,但至少创建与输入字符串中的字符数量相同的数组,因此在性能方面可能不是最优的。

1
    StringBuilder result = new StringBuilder();

    foreach (Char singleCharacter in str)
    {
        result.Append(singleCharacter.Equals('[') ? "[[]" : singleCharacter.Equals(']') ? "[]]" : singleCharacter.ToString());
    }

    str = result.ToString();

0

我曾经遇到过完全相同的问题,所以我编写了一个辅助函数来解决这个问题。

    protected string ReplaceUsingDictionary(string subject, Dictionary<string,string> pairs)
    {
        StringBuilder sb = new StringBuilder(subject);

        sb.Replace("{", "{{").Replace("}", "}}");

        int i=0;
        foreach (string key in pairs.Keys.ToArray())
        {
            sb.Replace(
                key.Replace("{", "{{").Replace("}", "}}"), 
                "{" + i + "}"
            );

            i++;
        }

        return string.Format(sb.ToString(), pairs.Values.ToArray());
    }

// usage
Dictionary<string, string> replacements = new Dictionary<string, string>();
replacements["["] = "[[]";
replacements["]"] = "[]]";

string mystr = ReplaceWithDictionary("[HelloWorld]", replacements); // returns [[]HelloWorld[]]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接