2010-02-18 13 views
7

Mam ciąg znaków zawierający 16 znaków alfanumerycznych, np. F4194E7CC775F003. Chciałbym sformatować go jako F419-4E7C-C775-F003.Formatowanie ciągu alfanumerycznego

Próbowałem za pomocą

string.Format("{0:####-####-####-####}","F4194E7CC775F003"); 

ale to nie działa, ponieważ nie jest to wartość liczbowa.

Więc wymyśliłem następujące:

public class DashFormatter : IFormatProvider, ICustomFormatter 
{ 
    public object GetFormat(Type formatType) 
    { 
    return this; 
    } 

    public string Format(string format, object arg, IFormatProvider formatProvider) 
    { 
    char[] chars = arg.ToString().ToCharArray(); 
    StringBuilder sb = new StringBuilder(); 

    for (int i = 0; i < chars.Length; i++) 
    { 
     if (i > 0 && i % 4 == 0) 
     { 
     sb.Append('-'); 
     } 

     sb.Append(chars[i]); 
    } 

    return sb.ToString(); 
    } 
} 

i za pomocą

string.Format(new DashFormatter(), "{0}", "F4194E7CC775F003"); 

udało mi się rozwiązać ten problem, jednak miałem nadzieję, istnieje lepszy/prostszy sposób to zrobić to? Być może magia LINQ?

Dzięki.

+0

myślałem, że to było dość proste, ale, niestety, to nie działa: 'string.Format (" {0} {1} {2} {3} - { 4} {5} {6} {7} - {8} {9} {10} {11} - {12} {13} {14} {15} ", aString.ToCharArray()); ciąg' – devuxer

+0

. format wymaga listy parametrów. aString.ToCharArray() jest postrzegany jako jeden parametr tablicy. – Carra

Odpowiedz

8

Można to zrobić w jednej linii bez Linq:

 StringBuilder splitMe = new StringBuilder("F4194E7CC775F003"); 
     string joined = splitMe.Insert(12, "-").Insert(8, "-").Insert(4, "-").ToString(); 
+0

+1 lepsze niż moje i lepszy niż którykolwiek z rozwiązań LINQ –

+0

Dodano stringbuilder. – Carra

+0

Zastanawiam się, który był bardziej wydajny, twój czy mój, więc zrobiłem szybki test porównawczy - twój jest dwa razy szybszy ;-) –

0
char[] chars = "F4194E7CC775F003".ToCharArray(); 
      var str = string.Format("{0}-{1}-{2}-{3}" 
            , new string(chars.Take(4).ToArray()) 
            , new string(chars.Skip(4).Take(4).ToArray()) 
            , new string(chars.Skip(8).Take(4).ToArray()) 
            , new string(chars.Skip(12).Take(4).ToArray()) 
       ); 
+0

Całkiem brzydki, ale LINQ rzeczywiście ;-) – Steven

+1

Przykro mi, ale wygląda to okropnie nieefektywnie, jak algorytm Schlemiela Malarza (http://www.joelonsoftware.com/articles/fog0000000319.html) –

+0

Loool, tak brzydki :) –

1

Jeśli chcesz LINQ:

var formatted = string.Join("-", Enumerable.Range(0,4).Select(i=>s.Substring(i*4,4)).ToArray()); 

A jeśli chcesz to wydajny:

var sb = new StringBuilder(19); 
sb.Append(s,0,4); 
for(var i = 1; i < 4; i++) 
{ 
sb.Append('-'); 
sb.Append(s,i*4, 4); 
} 
return sb.ToString(); 

Nie testowałem tego testu, ale myślę, że byłby szybki er następnie StringBuilder.Insert, ponieważ nie przesuwa reszty ciągu wiele razy, po prostu zapisuje 4 znaki. Nie można również ponownie przydzielić łańcucha bazowego, ponieważ jest wstępnie przypisany do 19 znaków na początku.

+0

tak cholernie coool :) –

+1

ale myślę, że brakuje zaginania var s = string.Join ("-", Enumerable.Range (0, 4). Wybierz (i => "F4194E7CC775F003" .Substring (i * 4, 4)). ToArray()); –

+0

może wyglądać fajnie, ale jest bardzo nieefektywny. Po prostu wykonałem kilka testów, a rozwiązanie Carry jest 3 razy szybsze. –

0

rozwiązanie Najprostszy mogę myśleć jest

 var text = "F4194E7CC775F003"; 
     var formattedText = string.Format(
      "{0}-{1}-{2}-{3}", 
      text.Substring(0, 4), 
      text.Substring(4, 4), 
      text.Substring(8, 4), 
      text.Substring(12, 4)); 
+0

taki sam jak TiTaN, mniej brzydki;) – RvdK

+0

Rozwiązanie Carry jest dwa razy szybsze –

2

Można to zrobić za pomocą wyrażenia regularnego, choć nie wiem, co wykonanie byłoby to w porównaniu do innych metod.

string formattedString = Regex.Replace(yourString, "(\\S{4})\\B", "$1-"); 

Można umieścić to w metodę rozszerzenia dla łańcucha też, jeśli chcesz zrobić:

yourString.ToDashedFormat(); 
+0

Przepraszam, ale to jest 25 razy wolniej niż rozwiązanie Carry. –

+0

Ou! Cóż, powiedziałem, że nie wiedziałem, jaki będzie występ! –

1

podstawie Carra's answer Zrobiłem ten mały sposób użytkowy:

private static string ToDelimitedString(string input, int position, string delimiter) 
{ 
    StringBuilder sb = new StringBuilder(input); 

    int x = input.Length/position; 

    while (--x > 0) 
    { 
    sb = sb.Insert(x * position, delimiter); 
    } 

    return sb.ToString(); 
} 

You może go używać w następujący sposób:

string result = ToDelimitedString("F4194E7CC775F003", 4, "-"); 

I przypadek testowy:

[Test] 
public void ReturnsDelimitedString() 
{ 
    string input = "F4194E7CC775F003"; 

    string actual = ToDelimitedString(input, 4, "-"); 

    Assert.AreEqual("F419-4E7C-C775-F003", actual); 
}