2011-12-14 18 views
18

Czy istnieje metoda porównywania ciągów znaków, która zwróci wartość na podstawie pierwszego wystąpienia niezgodnego znaku między dwoma ciągami znaków?C# metoda porównywania ciągów zwracająca indeks pierwszego niezgodnego

tj

string A = "1234567890" 

string B = "1234567880" 

chciałbym dostać z powrotem wartość, która pozwoliłaby mi zobaczyć, że pierwsza occurance z przerwą pasującym jest A [8]

+2

toczy własną rękę nie możliwe jako (być może) metoda rozszerzenia? – glosrob

+8

+1 do sprawdzania, czy to już istnieje w standardowej bibliotece. –

+0

Całkowicie. Nic gorszego, że duma z polerowania naprawdę dobrego wdrożenia spada, gdy zdajesz sobie sprawę, że jest w ramach od 1.1! –

Odpowiedz

7
/// <summary> 
/// Gets a first different char occurence index 
/// </summary> 
/// <param name="a">First string</param> 
/// <param name="b">Second string</param> 
/// <param name="handleLengthDifference"> 
/// If true will return index of first occurence even strings are of different length 
/// and same-length parts are equals otherwise -1 
/// </param> 
/// <returns> 
/// Returns first difference index or -1 if no difference is found 
/// </returns> 
public int GetFirstBreakIndex(string a, string b, bool handleLengthDifference) 
{ 
    int equalsReturnCode = -1; 
    if (String.IsNullOrEmpty(a) || String.IsNullOrEmpty(b)) 
    { 
     return handleLengthDifference ? 0 : equalsReturnCode; 
    } 

    string longest = b.Length > a.Length ? b : a; 
    string shorten = b.Length > a.Length ? a : b;  
    for (int i = 0; i < shorten.Length; i++) 
    { 
     if (shorten[i] != longest[i]) 
     { 
      return i; 
     } 
    } 

    // Handles cases when length is different (a="1234", b="123") 
    // index=3 would be returned for this case 
    // If you do not need such behaviour - just remove this 
    if (handleLengthDifference && a.Length != b.Length) 
    { 
     return shorten.Length; 
    } 

    return equalsReturnCode; 
} 
+1

Czy istnieje powód, dla którego sprawdzasz 'a.Equals (b)' zamiast 'a == b'? Twój kod złamie się, jeśli "a" ma wartość null. –

+0

Wywołanie równości spowoduje powtórzenie całego ciągu znaków aż do pierwszego przerwania blokowania krótkich przypadków, zanim przetestujesz cały łańcuch. Nazwałbym "ReferenceEquals" jako skrót, ale pomijam resztę "Equals", ponieważ i tak jego praca zostanie zduplikowana. –

+0

Dzięki chłopaki za wskazanie tego – sll

3

metodę rozszerzenia wzdłuż linii poniżej by wykonać zadanie:

public static int Your_Name_Here(this string s, string other) 
{ 
    string first = s.Length < other.Length ? s : other; 
    string second = s.Length > other.Length ? s : other; 

    for (int counter = 0; counter < first.Length; counter++) 
    { 
     if (first[counter] != second[counter]) 
     { 
      return counter; 
     } 
    } 
    return -1; 
} 
+0

Co się stanie, jeśli 'inny' jest krótszy niż' s'? – Oded

+0

To bomba :) sprawiedliwy komentarz, zmieni się – glosrob

+0

Nazwy są okropne - preferuj odpowiedź poniżej od @ sll – glosrob

2

że nie wiem, ale to dość banalne:

public static int FirstUnmatchedIndex(this string x, string y) 
{ 
    if(x == null || y == null) 
    throw new ArgumentNullException(); 
    int count = x.Length; 
    if(count > y.Length) 
    return FirstUnmatchedIndex(y, x); 
    if(ReferenceEquals(x, y)) 
    return -1; 
    for(idx = 0; idx != count; ++idx) 
    if(x[idx] != y[idx]) 
     return idx; 
    return count == y.Length? -1 : count; 
} 

Jest to proste porównanie porządkowe. Zwykłe porównanie niewrażliwe na wielkość liter jest łatwą zmianą, ale określenie kultury jest trudne do zdefiniowania; "Weißbier" niedopasowanie "WEISSBIERS" na ostatnim S w drugim ciągu, ale czy to liczy się jako pozycja 8 lub pozycja 9?

+0

LOL, oczywiście, że nie @Oded, dzięki. –

+1

Hej ... wszyscy to robimy ... TAK, powinniśmy zintegrować kompilator online;) – Oded

+0

@Oded Służą mi słusznie, nazywając to "trywialnym". Cóż, jest, ale wciąż jest niedoskonałość w pierwszym szkicu każdej odpowiedzi. –

2

Jeśli .net 4.0 zainstalowany, może to być sposób:

string A = "1234567890"; 
    string B = "1234567880"; 

    char? firstocurrence = A.Zip(B, (p, q) => new { A = p, B = q }) 
     .Where(p => p.A != p.B) 
     .Select(p => p.A) 
     .FirstOrDefault(); 

edit:

chociaż, jeśli trzeba stanowisko:

int? firstocurrence = A.Zip(B, (p, q) => new { A = p, B = q }) 
      .Where(p => p.A != p.B) 
      .Select((p, i) => i) 
      .FirstOrDefault(); 
+0

Nie można znaleźć punktu, w którym "abc" niedopasowanie "abcdef". –

+0

Nie jest to wymagane w pytaniu. W każdym razie łatwo sprawdzić, czy dwa ciągi mają różną długość. – Francisco

+0

Niezupełnie, ponieważ aby znaleźć miejsce, w którym "abc123432343234" niedopasowania "abcdefghijk" wymaga się zrobienia czegoś, co mogłoby odpowiedzieć na to pytanie w pierwszej kolejności. –

0

możliwe napisać rozszerzenie ciągu jak

public static class MyExtensions 
{ 
    public static IList<char> Mismatch(this string str1, string str2) 
    { 
     var char1 = str1.ToCharArray(); 
     var char2 = str2.ToCharArray(); 
     IList<Char> Resultchar= new List<char>(); 
     for (int i = 0; i < char2.Length;i++) 
     { 
      if (i >= char1.Length || char1[i] != char2[i]) 
       Resultchar.Add(char2[i]); 
     } 
     return Resultchar; 
    } 
} 

Używaj go jak

var r = "1234567890".Mismatch("1234567880"); 

to nie jest zoptymalizowany algorytm dla znalezienia niedopasowania.

Jeśli jesteś zainteresowany tylko znaleźć pierwszy niedopasowanie,

public static Char FirstMismatch(this string str1, string str2) 
     { 
      var char1 = str1.ToCharArray(); 
      var char2 = str2.ToCharArray();    
      for (int i = 0; i < char2.Length;i++) 
      { 
       if (i >= char1.Length || char1[i] != char2[i]) 
        return char2[i]; 
      } 
      return ''c; 
     } 
Powiązane problemy