2010-03-30 21 views
10

Tüm alt dizeleri dizeden almam gerekiyor. ex
:
2 dize "aaaaaa" ve "cccccc" döndürürİki dizge arasındaki tüm alt dizeleri bul

StringParser.GetSubstrings("[start]aaaaaa[end] wwwww [start]cccccc[end]", "[start]", "[end]"); 

biz yuvalama yalnızca bir düzey olduğunu varsayalım. Regexp hakkında emin değilim, ama bence yararlı olacak.

+0

1 düzeyinde 'xxx yyy [uç] zzz [son] [start]' mümkündür [start]? – kennytm

+0

Bu imkansız. –

+0

HTML veya XML ayrıştırmak için bunu yapıyorsanız, daha iyi yollar vardır ... – Randolpho

cevap

31
private IEnumerable<string> GetSubStrings(string input, string start, string end) 
{ 
    Regex r = new Regex(Regex.Escape(start) + "(.*?)" + Regex.Escape(end)); 
    MatchCollection matches = r.Matches(input); 
    foreach (Match match in matches) 
     yield return match.Groups[1].Value; 
} 
+0

Neye ihtiyacım var, teşekkürler –

+3

+1 - özellikle Regex.Escape için :) –

2

Eşleştirme gereksinimlerinizi yöneten kuralları daha iyi tanımlamanız gerekecek. Herhangi bir eşleme veya arama kodu oluştururken, hangi girdilerin öngörüleceğine ve hangi çıktıları üretmeniz gerektiğine dair net olmanız gerekir. Bu soruları yakından değerlendirmezseniz buggy kodunu üretmek çok kolaydır. Bu ...

Düzenli ifadeler kullanabilmeniz gerekir. İç içe yerleştirme işlemi biraz daha karmaşık hale getirebilir ancak yine de yapılabilir (iç içe geçmiş senaryolarda eşleşmesini beklediğiniz öğeye bağlı olarak). Böyle bir şey başlamak gerekir:

var start = "[start]"; 
var end = "[end]"; 
var regEx = new Regex(String.Format("{0}(.*){1}", Regex.Escape(start), Regex.Escape(end))); 
var source = "[start]aaaaaa[end] wwwww [start]cccccc[end]"; 
var matches = regEx.Match(source); 

O ihtiyaçlarınız için bir işlev uygun yukarıdaki kodu sarmak için önemsiz olmalıdır.

2

Sen normal bir ifade kullanmak, ancak argümanlar üzerinde Regex.Escape aramaya hatırlıyorum: bu metinde yeni hatları olsa bile uyacak şekilde

public static IEnumerable<string> GetSubStrings(
    string text, 
    string start, 
    string end) 
{ 
    string regex = string.Format("{0}(.*?){1}", 
     Regex.Escape(start), 
     Regex.Escape(end)); 

    return Regex.Matches(text, regex, RegexOptions.Singleline) 
     .Cast<Match>() 
     .Select(match => match.Groups[1].Value); 
} 

Ben de SingleLine seçeneği eklendi.

4

Düzenli ifadeler kullanmayan ve yuvalamayı dikkate almayan bir çözüm.

public static IEnumerable<string> EnclosedStrings(
    this string s, 
    string begin, 
    string end) 
{ 
    int beginPos = s.IndexOf(begin, 0); 
    while (beginPos >= 0) 
    { 
     int start = beginPos + begin.Length; 
     int stop = s.IndexOf(end, start); 
     if (stop < 0) 
      yield break; 
     yield return s.Substring(start, stop - start); 
     beginPos = s.IndexOf(begin, stop+end.Length); 
    }   
} 
0

Canım sıkıldı ve böylece ben juharr ki (karakter 7k kadar dizeleri ve başlangıç ​​/ bitiş parametreleri için <b> etiket bulunsa benim veri kümesi üzerinde) kuşkularımı "kanıtlıyor" yararsız mikro kriter yapılan'un çözümü, genel olarak en hızlı olanıdır.

Sonuçları (1000000 yineleme * 20 test durumları):

juharr: 6371ms 
Jake: 6825ms 
Mark Byers: 82063ms 

NOT: Derleyen regex benim veri kümesi üzerinde çok şeyler hızlandırmak vermedi.

0

Regex içermeyen bir yöntem: iç içe geçme aracının

public static List<string> extract_strings(string src, string start, string end) 
{ 
    if (src.IndexOf(start) > 0) 
    { 
     src = src.Substring(src.IndexOf(start)); 
    } 
    string[] array1 = src.Split(new[] { start }, StringSplitOptions.None); 
    List<string> list = new List<string>(); 
    foreach (string value in array1) 
    { 
     if (value.Contains(end)) 
     { 
      list.Add(value.Split(new[] { end }, StringSplitOptions.None)[0]); 
     } 
    } 
    return list; 
} 
İlgili konular