2011-09-01 18 views
109

Czy istnieje lepszy sposób na zastąpienie ciągów?Zastępowanie wielu znaków w ciągu znaków

Jestem zaskoczony, że Replace nie pobiera tablicy znaków ani tablicy napisów. Sądzę, że mógłbym napisać własne rozszerzenie, ale byłem ciekawy, czy jest lepiej zbudowany, aby wykonać następujące czynności? Zauważ, że ostatnia zamiana jest ciągiem, a nie znakiem.

myString.Replace(';', '\n').Replace(',', '\n').Replace('\r', '\n').Replace('\t', '\n').Replace(' ', '\n').Replace("\n\n", "\n"); 

Dzięki.

Odpowiedz

141

Możesz użyć zamiany wyrażenia regularnego.

s/[;,\t\r ]|[\n]{2}/\n/g 
  • s/ na początku oznacza poszukiwanie
  • Znaki między [ i ] są znaki na wyszukiwanie (w dowolnej kolejności)
  • Drugi / ogranicza wyszukiwany tekst-na i tym zamień tekst

W języku angielskim, brzmi to następująco:

"Szukaj ; lub , lub \t lub \r lub (spacja) lub dokładnie dwa sekwencyjne \n i zastąpić go \n"

w języku C#, można wykonać następujące czynności: (po imporcie System.Text.RegularExpressions)

Regex pattern = new Regex("[;,\t\r ]|[\n]{2}"); 
pattern.Replace(myString, "\n"); 
+1

'\ t' i' \ r' są zawarte w '\ s'. Zatem twoje wyrażenie regularne jest równoważne '[;, \ s]'. – NullUserException

+2

A '\ s' jest faktycznie równoważne' [\ f \ n \ r \ t \ v] ', więc dodajesz tam pewne rzeczy, których nie było w oryginalnym pytaniu. Dodatkowo oryginalne pytanie wymaga 'Replace (" \ n \ n "," \ n ")' którego twoje regex nie obsługuje. – NullUserException

+0

Nie wiem, dlaczego RegEx uciekł mi z głowy ... dzięki. – zgirod

0

Zastosowanie Regex.Replace, coś takiego:

string input = "This is text with far too much " + 
       "whitespace."; 
    string pattern = "[;,]"; 
    string replacement = "\n"; 
    Regex rgx = new Regex(pattern); 

Oto więcej informacji na temat tego MSDN documentation for RegEx.Replace

85

Jeśli czujesz się szczególnie mądry i nie chcesz, aby użyć wyrażenia regularnego:

char[] separators = new char[]{' ',';',',','\r','\t','\n'}; 

string s = "this;is,\ra\t\n\n\ntest"; 
string[] temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries); 
s = String.Join("\n", temp); 

Można owinąć to w metodzie wydłużania przy niewielkim wysiłku, jak również.

Edit: Albo po prostu poczekać 2 minuty i skończę pisać to w każdym razie :)

public static class ExtensionMethods 
{ 
    public static string Replace(this string s, char[] separators, string newVal) 
    { 
     string[] temp; 

     temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries); 
     return String.Join(newVal, temp); 
    } 
} 

i voila ...

char[] separators = new char[]{' ',';',',','\r','\t','\n'}; 
string s = "this;is,\ra\t\n\n\ntest"; 

s = s.Replace(separators, "\n"); 
+2

+1, i mam nadzieję, że nie masz nic przeciwko, ale użyłem nieco zmodyfikowanej wersji twojej metody na moim blogu. http://learncsharp.org/how-to-properly-and-safely-accessa-a-database-w-a-net-net/ –

41

Można użyć funkcji zbiorczej LINQ to:

string s = "the\nquick\tbrown\rdog,jumped;over the lazy fox."; 
char[] chars = new char[] { ' ', ';', ',', '\r', '\t', '\n' }; 
string snew = chars.Aggregate(s, (c1, c2) => c1.Replace(c2, '\n')); 

Oto metoda rozszerzenia:

public static string ReplaceAll(this string seed, char[] chars, char replacementCharacter) 
{ 
    return chars.Aggregate(seed, (str, cItem) => str.Replace(cItem, replacementCharacter)); 
} 
13

Jest to najkrótsza droga:

myString = Regex.Replace(myString, @"[;,\t\r ]|[\n]{2}", "\n"); 
+1

Ta jedna wkładka również pomaga, gdy jest to potrzebne w inicjalizatorach. –

5

Ohhh, horror wydajność! Odpowiedź jest nieco przestarzała, ale wciąż ...

public static class StringUtils 
{ 
    #region Private members 

    [ThreadStatic] 
    private static StringBuilder m_ReplaceSB; 

    private static StringBuilder GetReplaceSB(int capacity) 
    { 
     var result = m_ReplaceSB; 

     if (null == result) 
     { 
      result = new StringBuilder(capacity); 
      m_ReplaceSB = result; 
     } 
     else 
     { 
      result.Clear(); 
      result.EnsureCapacity(capacity); 
     } 

     return result; 
    } 


    public static string ReplaceAny(this string s, char replaceWith, params char[] chars) 
    { 
     if (null == chars) 
      return s; 

     if (null == s) 
      return null; 

     StringBuilder sb = null; 

     for (int i = 0, count = s.Length; i < count; i++) 
     { 
      var temp = s[i]; 
      var replace = false; 

      for (int j = 0, cc = chars.Length; j < cc; j++) 
       if (temp == chars[j]) 
       { 
        if (null == sb) 
        { 
         sb = GetReplaceSB(count); 
         if (i > 0) 
          sb.Append(s, 0, i); 
        } 

        replace = true; 
        break; 
       } 

      if (replace) 
       sb.Append(replaceWith); 
      else 
       if (null != sb) 
        sb.Append(temp); 
     } 

     return null == sb ? s : sb.ToString(); 
    } 
} 
0

Performance-Wise to prawdopodobnie nie jest najlepsze rozwiązanie, ale działa.

var str = "filename:with&bad$separators.txt"; 
char[] charArray = new char[] { '#', '%', '&', '{', '}', '\\', '<', '>', '*', '?', '/', ' ', '$', '!', '\'', '"', ':', '@' }; 
foreach (var singleChar in charArray) 
{ 
    str = str.Replace(singleChar, '_'); 
} 
2

Struny są tylko niezmienne tablice char

Trzeba tylko zrobić to zmienne:

  • albo za pomocą StringBuilder
  • pójść w świat unsafe i grać ze wskaźnikami (niebezpieczne jednak)

i spróbuj co najmniej tyle razy powtarzać tablicę znaków.

Przykład z StringBuilder

public static void MultiReplace(this StringBuilder builder, char[] toReplace, char replacement) 
    { 
     HashSet<char> set = new HashSet<char>(toReplace); 
     for (int i = 0; i < builder.Length; ++i) 
     { 
      var currentCharacter = builder[i]; 
      if (set.Contains(currentCharacter)) 
      { 
       builder[i] = replacement; 
      } 
     } 
    } 

Wtedy po prostu trzeba używać go tak:

var builder = new StringBuilder("my bad,url&slugs"); 
builder.MultiReplace(new []{' ', '&', ','}, '-'); 
var result = builder.ToString();