2010-04-14 77 views
48

Tôi có chuỗi lớn cần phân tích và tôi cần tìm tất cả các phiên bản của extract"(me,i-have lots. of]punctuation và lưu chỉ mục của từng chuỗi vào danh sách.Tìm tất cả các vị trí của chuỗi con trong một chuỗi lớn hơn trong C#

Vì vậy, hãy nói đoạn chuỗi này ở đầu và giữa của chuỗi lớn hơn, cả hai chuỗi sẽ được tìm thấy và chỉ mục của chúng sẽ được thêm vào List. và List sẽ chứa 0 và chỉ mục khác bất kể nó là gì.

Tôi đã chơi xung quanh và string.IndexOf hiện gần như những gì tôi đang tìm kiếm và tôi đã viết một số mã - nhưng nó không hoạt động và tôi không thể tìm ra chính xác những gì sai :

List<int> inst = new List<int>(); 
int index = 0; 
while (index < source.LastIndexOf("extract\"(me,i-have lots. of]punctuation", 0) + 39) 
{ 
    int src = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index); 
    inst.Add(src); 
    index = src + 40; 
} 
  • inst = danh sách
  • source = chuỗi lớn

Bất kỳ ý tưởng nào tốt hơn?

Trả lời

90

Dưới đây là một phương pháp mở rộng ví dụ cho nó:

public static List<int> AllIndexesOf(this string str, string value) { 
    if (String.IsNullOrEmpty(value)) 
     throw new ArgumentException("the string to find may not be empty", "value"); 
    List<int> indexes = new List<int>(); 
    for (int index = 0;; index += value.Length) { 
     index = str.IndexOf(value, index); 
     if (index == -1) 
      return indexes; 
     indexes.Add(index); 
    } 
} 

Nếu bạn đặt này vào một lớp tĩnh và import namespace với using, nó xuất hiện như một phương pháp trên bất kỳ chuỗi, và bạn chỉ có thể làm:

List<int> indexes = "fooStringfooBar".AllIndexesOf("foo"); 

Để biết thêm thông tin về phương pháp khuyến nông, http://msdn.microsoft.com/en-us/library/bb383977.aspx

Cũng cùng sử dụng một iterator:

public static IEnumerable<int> AllIndexesOf(this string str, string value) { 
    if (String.IsNullOrEmpty(value)) 
     throw new ArgumentException("the string to find may not be empty", "value"); 
    for (int index = 0;; index += value.Length) { 
     index = str.IndexOf(value, index); 
     if (index == -1) 
      break; 
     yield return index; 
    } 
} 
+5

Tại sao không sử dụng IEnumerable và chỉ số lợi nhuận thay vì danh sách chỉ mục? – m0sa

+1

@ m0sa: Tốt. Thêm một phiên bản khác chỉ để cho niềm vui của nó. –

+0

Việc sử dụng năng suất có bất kỳ tỷ lệ nào trong hiệu suất không? Việc thu hồi của các đối tượng trở nên không đồng bộ hoặc lười biếng? Os là nó chỉ cú pháp đường và cả hai mã đều giống nhau? – PedroC88

0

Dựa trên mã tôi đã sử dụng cho việc tìm kiếm nhiều trường hợp của một chuỗi trong một chuỗi lớn hơn, mã của bạn sẽ trông như thế:

List<int> inst = new List<int>(); 
int index = 0; 
while (index >=0) 
{ 
    index = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index); 
    inst.Add(index); 
    index++; 
} 
1
public List<int> GetPositions(string source, string searchString) 
{ 
    List<int> ret = new List<int>(); 
    int len = searchString.Length; 
    int start = -len; 
    while (true) 
    { 
     start = source.IndexOf(searchString, start + len); 
     if (start == -1) 
     { 
      break; 
     } 
     else 
     { 
      ret.Add(start); 
     } 
    } 
    return ret; 
} 

Gọi nó như thế này:

List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob"); 
// list will contain 0, 22, 26 
10

Tại sao bạn không sử dụng lớp RegEx được tích hợp sẵn:

public static IEnumerable<int> GetAllIndexes(this string source, string matchString) 
{ 
    matchString = Regex.Escape(matchString); 
    foreach (Match match in Regex.Matches(source, matchString)) 
    { 
     yield return match.Index; 
    } 
} 

Nếu bạn cần sử dụng lại biểu thức, hãy biên dịch nó và lưu nó ở đâu đó. Thay đổi param matchString thành một đối sánh Regex trong một quá tải khác cho trường hợp tái sử dụng.

+0

Điều này không biên dịch – Anshul

+0

'chỉ mục' là gì? Nó không được định nghĩa ở đâu cả. – Saggio

+0

xấu của tôi đó là một tàn dư. Xóa dòng đó. – csaam

7

sử dụng LINQ

public static IEnumerable<int> IndexOfAll(this string sourceString, string subString) 
{ 
    return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index); 
} 
+1

Bạn đã quên thoát khỏi subString. – csaam

+0

true ... true ... – ehosca

0

@csam là đúng về mặt lý thuyết, mặc dù mã của ông sẽ không complie và có thể được refractored để

public static IEnumerable<int> IndexOfAll(this string sourceString, string matchString) 
{ 
    matchString = Regex.Escape(matchString); 
    return from Match match in Regex.Matches(sourceString, matchString) select match.Index; 
} 
+0

nếu mã của anh ấy sai, bạn có thể chỉnh sửa bài đăng của mình để sửa nó – caesay

+0

Tôi đã không nhận thấy điều đó. Tôi phải thừa nhận là không muốn làm điều đó, chỉ trong trường hợp tôi sai, mặc dù tôi không nghĩ rằng tôi. – arame3333

+0

đó không phải là ý tưởng tốt để sử dụng regex cho chuỗi lớn. Cách tiếp cận này chiếm rất nhiều bộ nhớ. – W92

4

bóng phiên bản + trường hợp bỏ qua hỗ trợ:

public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false) 
{ 
    if (string.IsNullOrWhiteSpace(str) || 
     string.IsNullOrWhiteSpace(substr)) 
    { 
     throw new ArgumentException("String or substring is not specified."); 
    } 

    var indexes = new List<int>(); 
    int index = 0; 

    while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1) 
    { 
     indexes.Add(index++); 
    } 

    return indexes.ToArray(); 
} 
0
public static Dictionary<string, IEnumerable<int>> GetWordsPositions(this string input, string[] Susbtrings) 
{ 
    Dictionary<string, IEnumerable<int>> WordsPositions = new Dictionary<string, IEnumerable<int>>(); 
    IEnumerable<int> IndexOfAll = null; 
    foreach (string st in Susbtrings) 
    { 
     IndexOfAll = Regex.Matches(input, st).Cast<Match>().Select(m => m.Index); 
     WordsPositions.Add(st, IndexOfAll); 

    } 
    return WordsPositions; 
} 
1

Hi trả lời thoải mái bởi @Matti Virkkunen

public static List<int> AllIndexesOf(this string str, string value) { 
    if (String.IsNullOrEmpty(value)) 
     throw new ArgumentException("the string to find may not be empty", "value"); 
    List<int> indexes = new List<int>(); 
    for (int index = 0;; index += value.Length) { 
     index = str.IndexOf(value, index); 
     if (index == -1) 
      return indexes; 
     indexes.Add(index); 
     index--; 
    } 
} 

Nhưng điều này bao gồm kiểm tra những trường hợp như AOOAOOA nơi chuỗi

là AOOA và AOOA

Output 0 và 3

0

Without Regex, sử dụng chuỗi loại so sánh:

string search = "123aa456AA789bb9991AACAA"; 
string pattern = "AA"; 
Enumerable.Range(0, search.Length) 
    .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; }) 
    .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length),StringComparison.OrdinalIgnoreCase)) 
    .Select(searchbit => searchbit.Index) 

Điều này retur ns {3,8,19,22}. Mẫu trống sẽ khớp với tất cả các vị trí.

Đối với nhiều mô hình:

string search = "123aa456AA789bb9991AACAA"; 
string[] patterns = new string[] { "aa", "99" }; 
patterns.SelectMany(pattern => Enumerable.Range(0, search.Length) 
    .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; }) 
    .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length), StringComparison.OrdinalIgnoreCase)) 
    .Select(searchbit => searchbit.Index)) 

này lợi nhuận {3, 8, 19, 22, 15, 16}

0

tôi nhận thấy rằng ít nhất hai giải pháp đề xuất không xử lý chồng chéo truy cập tìm kiếm. Tôi đã không đánh dấu cái được đánh dấu bằng dấu kiểm màu lục. Dưới đây là cách xử lý số lần truy cập tìm kiếm trùng lặp:

public static List<int> GetPositions(this string source, string searchString) 
    { 
     List<int> ret = new List<int>(); 
     int len = searchString.Length; 
     int start = -1; 
     while (true) 
     { 
      start = source.IndexOf(searchString, start +1); 
      if (start == -1) 
      { 
       break; 
      } 
      else 
      { 
       ret.Add(start); 
      } 
     } 
     return ret; 
    } 
Các vấn đề liên quan