Замена плохих символов строки плохими - PullRequest
8 голосов
/ 13 февраля 2012

Мне просто интересно, какой самый простой способ заменить строковые символы, которые должны быть заменены впоследствии.

Например:

var str = "[Hello World]";
//enclose all occurences of [ and ] with brackets[] 
str = str.Replace("[","[[]").Replace("]","[]]");
  • Желаемый результат: [[]Hello World[]]
  • Фактический результат: [[[]]Hello World[]]

Причина, очевидно, заключается во второй замене уже измененной строки.

Итак, как заменить все вхождения «плохих» символов на символы, содержащие «плохие» символы?


БыстрыйИзмерение всех подходов показало, что StringBuilder является наиболее эффективным способом.

190 КБ (все в миллисекундах)

  regexTime           40.5065  
  replaceTime         20.8891  
  stringBuilderTime    6.9776

7 МБ

  regexTime           1209.3529           
  replaceTime          403.3985   
  stringBuilderTime    175.2583

Кстати, прямой StringBuilder подход от John был в два раза быстрее, чем Aggregate подход от Sehe .

Я сделал из этого расширение:

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 голосов
/ 13 февраля 2012

Вот очень не крутой способ сделать это. Но у него есть преимущество: я думаю, что он довольно близок к защите от дурака и не использует регулярные выражения (если вы не хотите использовать регулярные выражения).

StringBuilder sb = new StringBuilder();
foreach (char c in str.ToCharArray()) {
    if (c == '[' || c == ']') {
        sb.Append('[' + c + ']');
    }
    else {
        sb.Append(c);
    }
}
string result = sb.ToString();
4 голосов
/ 13 февраля 2012

А как же:

str = str.Replace("[", "$1[$2")
         .Replace("]", "$1]$2")
         .Replace("$1", "[")
         .Replace("$2", "]");
3 голосов
/ 13 февраля 2012

Как насчет этого элегантного подхода регулярного выражения:

Regex.Replace("[Hello World]", @"[\[\]]", "[$0]");

Юнит-тест это?

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

Тест пройден


Edit @ JohnMcGrant

Вот немного менее неэффективная версия вашего кода, которая, кстати, имеет точно такое же поведение, что и приведенное выше регулярное выражение:

string result = input.Aggregate(new StringBuilder(), (a, c) =>
    -1 != "[]".IndexOf(c) ? a.AppendFormat("[{0}]", c) : a.Append(c)).ToString();
1 голос
/ 13 февраля 2012
    StringBuilder result = new StringBuilder();

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

    str = result.ToString();
1 голос
/ 13 февраля 2012

Как насчет:

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

Обратите внимание, что это позволяет избежать проблемы с несколькими циклами, но создает как минимум столько массивов, сколько имеется символов во входной строке, поэтому она может быть неоптимальной с точки зрения производительности.

0 голосов
/ 13 февраля 2012

У меня была точно такая же проблема, поэтому я сделал вспомогательную функцию, чтобы сделать именно это

    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[]]
...