2012-02-13 13 views
8

Daha sonra değiştirilmesi gereken bir dize karakterleri değiştirmenin en kolay yolunun ne olduğunu merak ettim. ÖrneğinBir String'in bozuk karakterlerini kötü karakterlerle değiştirme

:

var str = "[Hello World]"; 
//enclose all occurences of [ and ] with brackets[] 
str = str.Replace("[","[[]").Replace("]","[]]"); 
  • istenen sonucu: [[]Hello World[]]
  • gerçek sonuç: [[[]]Hello World[]]

nedeni ikinci zaten değiştirilmiş dizesi yerine besbelli.

"Kötü" karakterlerin tüm oluşumları "kötü" karakterler içeren karakterlerle nasıl değiştirilir? tüm yaklaşımların


Hızlı bir ölçüm StringBuilder en etkili yoludur ortaya çıkarmıştır.

regexTime   40.5065 
    replaceTime   20.8891 
    stringBuilderTime 6.9776 

7MB dosyasında (bütün milisaniye cinsinden)

190KB dosya

arada
regexTime   1209.3529   
    replaceTime   403.3985 
    stringBuilderTime 175.2583 

, John edildi doğrudan StringBuilder yaklaşım iki katkadar hızlı, Sehe numaralı telefondan yaklaşmaktadır.

ben bunun dışında bir uzantısı yaptık:

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[]{'[', ']'},"[","]"); 
+3

+1 Güzel bir şekilde ölçülmüş, Tim. –

cevap

5

İşte bunu yapmak için çok unolol yoludur. Ancak, kusursuz, sanırım ve regex kullanmamaya oldukça yakın bir avantajdır (regex kullanmamanız durumunda).

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

Birim testi o: bu zarif düzenli ifade yaklaşımı hakkında

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

Teşekkürler. Çoğu zaman uncool yolu en iyi/en hızlı olanıdır. Bir uzantı yönteminde gizlendiğinde sorun yok;) –

4

Ne hakkında:

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

Monitör fikirlerini aracı olarak kullanarak güzel bir fikir. – Oded

+4

Ancak, dizenin önceden bu monitör değerlerini içermediğini ya da aynı şeyin tekrar olup olmadığını kontrol etmelisiniz. Örnek: 'Merhaba [1 $]' – Oliver

+0

Gerçek karakter değerlerini değiştirmeden önce monitör değerlerini + gerçek karakterleri değiştirecek düzenleme, Oliver'ın problemini (bir duvar ve merdivenlerde de olsa) çözebilir, ancak okunabilirlik pahasına , Bence. –

1

ne dersiniz: Bu ancak birden döngüler sorunu önler olduğunu

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

Not Giriş dizgisinde karakterler olduğundan en az sayıda diziyi oluşturur, böylece performans açısından en uygun olmayabilir.

+0

+1 LINQ kullanımı yaratın. Çok performanslı değil ... :) – sehe

3

ne olacak?

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

Testi


Düzenleme @JohnMcGrant İşte

arada, sahip kodunuzda, yukarıdaki regex tam olarak aynı davranışı biraz daha az verimsiz versiyonudur geçti:

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

Bunun olmayacağını varsaymak büyük olasılıkla güvenlidir, ancak parantez içindeki metin parantez içinde parantez içerebilirse, belki de bir şekilde kaçtı. Bu regex kırmak olmaz mı? –

+0

@JohnMGant: Hayır, çünkü bu şartların değiştiği anlamına geliyor. Ya soru farklı olsaydı? Bu cevabı kırmak mı? Hayır! – sehe

+0

@ JohnMGant'ın sürümüne dayalı alternatif bir yaklaşım eklendi. Ben regex hala en iyi yaklaşım olduğunu düşünüyorum :) – sehe

1
StringBuilder result = new StringBuilder(); 

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

    str = result.ToString(); 
0

Tam olarak aynı problemi yaşadım, bu yüzden ben sadece