2016-02-18 24 views
6

Có cách nào để nhận chuỗi con phù hợp từ chuỗi bằng cách so sánh bình đẳng văn hóa nhạy cảm không? Ví dụ, dưới văn hóa en-US, æae được coi là bằng nhau. "Encyclopædia".IndexOf("aed") đánh giá là 8, biểu thị kết quả phù hợp; Tuy nhiên, có cách nào để trích xuất chuỗi con phù hợp, æd, không liên quan đến việc lặp qua chuỗi nguồn không? Lưu ý rằng độ dài của các bề mặt tìm kiếm và kết hợp có thể khác nhau bởi một vài ký tự.Nhận chuỗi con từ chuỗi sử dụng so sánh văn hóa nhạy cảm

+0

gì về việc sử dụng một biểu thức chính quy như '(ae | æ) d'? – juharr

+0

@juharr: Regex sẽ là quá mức cần thiết (và giới thiệu các sắc thái riêng của nó). Tôi cần điều này để thực hiện chức năng rất đa năng, chẳng hạn như phương thức mở rộng 'String.Replace' nhạy cảm về văn hóa. – Douglas

+0

Câu hỏi liên quan: [Làm cách nào để tôi có thể thực hiện thao tác "bắt đầu bằng" nhạy cảm với văn hóa từ giữa một chuỗi?] (Http://stackoverflow.com/q/15980310/1149773) (bởi Jon Skeet), [Độ dài của chuỗi con phù hợp với phương thức 'String.IndexOf' nhạy cảm về văn hóa] (http://stackoverflow.com/q/20480016/1149773). – Douglas

Trả lời

2

Tôi đã giải quyết điều này bằng cách trước tiên gọi số IndexOf để nhận vị trí bắt đầu của trận đấu, sau đó lặp lại cố gắng xác định độ dài của nó. Tôi đã tối ưu hóa cho đường dẫn nóng của trận đấu có cùng chiều dài với chuỗi con được chỉ định; trong trường hợp đó, chỉ có một so sánh duy nhất được thực hiện.

public static class StringExtensions 
{ 
    public static void Find(this string source, string substring, StringComparison comparisonType, out int matchIndex, out int matchLength) 
    { 
     Find(source, substring, 0, source.Length, comparisonType, out matchIndex, out matchLength); 
    } 

    public static void Find(this string source, string substring, int searchIndex, StringComparison comparisonType, out int matchIndex, out int matchLength) 
    { 
     Find(source, substring, searchIndex, source.Length - searchIndex, comparisonType, out matchIndex, out matchLength); 
    } 

    public static void Find(this string source, string substring, int searchIndex, int searchLength, StringComparison comparisonType, out int matchIndex, out int matchLength) 
    { 
     matchIndex = source.IndexOf(substring, searchIndex, searchLength, comparisonType); 
     if (matchIndex == -1) 
     { 
      matchLength = -1; 
      return; 
     } 

     matchLength = FindMatchLength(source, substring, searchIndex, searchLength, comparisonType, matchIndex); 

     // Defensive programming, but should never happen 
     if (matchLength == -1) 
      matchIndex = -1; 
    } 

    private static int FindMatchLength(string source, string substring, int searchIndex, int searchLength, StringComparison comparisonType, int matchIndex) 
    { 
     int matchLengthMaximum = searchLength - (matchIndex - searchIndex); 
     int matchLengthInitial = Math.Min(substring.Length, matchLengthMaximum); 

     // Hot path: match length is same as substring length. 
     if (Compare(source, matchIndex, matchLengthInitial, substring, 0, substring.Length, comparisonType) == 0) 
      return matchLengthInitial; 

     int matchLengthDecrementing = matchLengthInitial - 1; 
     int matchLengthIncrementing = matchLengthInitial + 1; 

     while (matchLengthDecrementing >= 0 || matchLengthIncrementing <= matchLengthMaximum) 
     { 
      if (matchLengthDecrementing >= 0) 
      { 
       if (Compare(source, matchIndex, matchLengthDecrementing, substring, 0, substring.Length, comparisonType) == 0) 
        return matchLengthDecrementing; 

       matchLengthDecrementing--; 
      } 

      if (matchLengthIncrementing <= matchLengthMaximum) 
      { 
       if (Compare(source, matchIndex, matchLengthIncrementing, substring, 0, substring.Length, comparisonType) == 0) 
        return matchLengthIncrementing; 

       matchLengthIncrementing++; 
      } 
     } 

     // Should never happen 
     return -1; 
    } 

    private static int Compare(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB, StringComparison comparisonType) 
    { 
     switch (comparisonType) 
     { 
      case StringComparison.CurrentCulture: 
       return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); 

      case StringComparison.CurrentCultureIgnoreCase: 
       return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); 

      case StringComparison.InvariantCulture: 
       return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); 

      case StringComparison.InvariantCultureIgnoreCase: 
       return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); 

      case StringComparison.Ordinal: 
       return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.Ordinal); 

      case StringComparison.OrdinalIgnoreCase: 
       return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.OrdinalIgnoreCase); 

      default: 
       throw new ArgumentException("The string comparison type passed in is currently not supported.", nameof(comparisonType)); 
     } 
    } 
} 

sử dụng mẫu:

int index, length; 
source.Find(remove, StringComparison.CurrentCulture, out index, out length); 
string clean = index < 0 ? source : source.Remove(index, length); 
Các vấn đề liên quan