Найти все подстроки между двумя строками

Мне нужно получить все подстроки из строки.
Например:

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

который возвращает 2 строки "aaaaaa" и "cccccc" Предположим, что мы имеем только один уровень гнездования. Не уверен в regexp, но я думаю, что он будет полезен.

Ответ 1

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

Ответ 2

Здесь существует решение, которое не использует регулярные выражения и не учитывает вложенность.

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

Ответ 3

Вам нужно будет лучше определить правила, которые будут соответствовать вашим потребностям. При создании любого типа кода соответствия или поиска вам необходимо четко различать, какие данные вы ожидаете и какие выходы вам нужно произвести. Очень легко создать ошибочный код, если вы не будете внимательно изучать эти вопросы. Тем не менее...

Вы должны иметь возможность использовать регулярные выражения. Вложение может сделать его несколько более сложным, но все же выполнимым (в зависимости от того, что вы ожидаете от соответствия в вложенных сценариях). Что-то вроде этого должно начаться:

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

Это должно быть тривиально обернуть вышеприведенный код в функцию, соответствующую вашим потребностям.

Ответ 4

Вы можете использовать регулярное выражение, но не забудьте вызвать Regex.Escape в своих аргументах:

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

Я также добавил параметр SingleLine, чтобы он соответствовал, даже если в тексте есть новые строки.

Ответ 5

Мне было скучно, и, таким образом, я сделал бесполезный микро-тест, который "доказывает" (на моем наборе данных, который содержит строки до 7 тыс. символов и теги <b> для параметров начала и конца). Мое подозрение, что решение juharr является самый быстрый из трех.

Результаты (1000000 итераций * 20 тестовых случаев):

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

ПРИМЕЧАНИЕ. Скомпилированное регулярное выражение не сильно ускорило мои данные.

Ответ 6

Метод без регулярных выражений:

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