2010-03-30 8 views
10

Je dois obtenir toutes les sous-chaînes de la chaîne.
Ex:
Trouver toutes les sous-chaînes entre deux chaînes

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

qui retourne 2 chaîne "aaaaaa" et "CCCCCC" Supposons que nous ayons un seul niveau d'imbrication. Je ne suis pas sûr de regexp, mais je pense que ce sera utile.

+0

1 niveau de moyens d'emboîtement '[démarrer] xxx [démarrer] yyy [end] zzz [end]' est possible? – kennytm

+0

C'est impossible. –

+0

Si vous faites cela pour analyser HTML ou XML, il existe de meilleurs moyens ... – Randolpho

Répondre

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

Exact ce dont j'ai besoin, merci –

+3

+1 - en particulier pour le Regex.Escape :) –

2

Vous allez avoir besoin de mieux définir les règles qui régissent vos besoins correspondants. Lors de la création de tout type de code de correspondance ou de recherche, vous devez définir clairement les entrées que vous prévoyez et celles que vous devez produire. Il est très facile de produire du code buggé si vous ne prenez pas ces questions en considération. Cela dit ...

Vous devriez pouvoir utiliser des expressions régulières. L'imbrication peut le rendre un peu plus compliqué mais toujours réalisable (en fonction de ce que vous attendez dans les scénarios imbriqués). Quelque chose comme devrait vous aider à démarrer:

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); 

Il devrait être trivial d'enrouler le code ci-dessus dans une fonction appropriée à vos besoins.

2

Vous pouvez utiliser une expression régulière, mais rappelez-vous d'appeler Regex.Escape sur vos arguments:

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); 
} 

J'ai aussi ajouté l'option SingleLine afin qu'il corresponde même s'il y a de nouvelles lignes dans votre texte.

4

Voici une solution qui n'utilise pas d'expressions régulières et ne prend pas en compte l'imbrication.

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

Je me suis ennuyé, et donc j'ai fait une référence micro inutile qui « prouve » (sur mon jeu de données, qui a des chaînes jusqu'à 7k de caractères et <b> balises pour les paramètres de début/fin) Je soupçonne que juharr La solution de est la plus rapide des trois.

résultats (1000000 itérations * 20 cas de test):

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

NOTE: Compilé regex n'a pas accélérer les choses beaucoup sur mon ensemble de données.

0

méthode Regex libres:

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; 
} 
Questions connexes