2015-12-09 2 views
1

Например, если у меня был текст, какRegex найти самый длинный фрагмент текста, где последняя буква слова соответствует первой букве следующего слова

first line of text 
badger Royal lemon, night trail 
light of. Random string of words 
that don't match anymore. 

Мой результат должен был бы быть строки слов, где последний символ каждого слово соответствует первому символу следующего слова, даже если между ними есть разделители. В этом случае:

badger Royal lemon, night trail 
light 

Что такое самый простой способ сделать это, если я хочу использовать Regex?

+2

Что о попытке что-нибудь! Кроме того, реализация этой функции с немного большим количеством кода (с петлями) кажется довольно простой. – varocarbas

+0

Я согласен с @varocarbas, кажется, что это проще сделать с циклом, а не пытаться адаптировать регулярное выражение. – test

+0

regex ... кошмар. Напишите от руки это на любом языке. Я думаю, что это можно решить в O (N). RegEx не подходит для поиска значения «max» ... RegEx хорош для поиска шаблонов, а не максимальных значений или минимальных значений. –

ответ

0

Я знаю, что это НЕ РЕЖИМ-реализация, но ... возможно, это помогает. Это простая реализация в C#:

public static string Process (string s) 
    { 
     var split = s.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); 

     if (split.Length < 2) 
      return null; // impossible to find something if the length is not at least two 

     string currentString = null; 
     string nextString = null; 
     for (var i = 0; i < split.Length - 1; i++) 
     { 
      var str = split[i]; 
      if (str.Length == 0) continue; 

      var lastChar = str[str.Length - 1]; 

      var nextStr = split[i + 1]; 
      if (nextStr.Length == 0) continue; 

      var nextChar = nextStr[0]; 
      if (lastChar == nextChar) 
      { 
       if (currentString == null) 
       { 
        currentString = str; 
        nextString = nextStr.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0]; 
       } 
       else 
       { 
        if (str.Length > currentString.Length) 
        { 
         currentString = str; 
         nextString = nextStr.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0]; 
        } 
       } 


      } 
     } 

     return currentString == null ? null : currentString + "\n" + nextString; 
    } 
2

Регулярное выражение, которое соответствует каждой из последовательностей слов будет:

(?:\b\w+(\w)\b[\W]*(?=\1))*\1\w+ 

Regular expression visualization

Вам нужно настроить \W часть в зависимости от ваших правил, касающихся полных остановок, полуколоний, запятых и т. д.

Обратите внимание, что это также предполагает единственную букву слова прерывают последовательность.

Вы можете затем цикл над каждым из вхождений и найти самый длинный:

try { 
    Regex regexObj = new Regex(@"(?:\b\w+(\w)\b[\W+]*(?=\1))*\1\w+", RegexOptions.IgnoreCase | RegexOptions.Singleline); 
    Match matchResults = regexObj.Match(subjectString); 
    while (matchResults.Success) { 
     // matched text: matchResults.Value 
     // match start: matchResults.Index 
     // match length: matchResults.Length 

     // @todo here test and keep the longest match. 

     matchResults = matchResults.NextMatch(); 
    } 
} catch (ArgumentException ex) { 
    // Syntax error in the regular expression 
} 

// (?:\b\w+(\w)\b[\W]*(?=\1))*\1\w+ 
// 
// Options: Case insensitive; Exact spacing; Dot doesn’t match line breaks; ^$ don’t match at line breaks; Numbered capture 
// 
// Match the regular expression below «(?:\b\w+(\w)\b[\W]*(?=\1))*» 
// Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» 
// Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b» 
// Match a single character that is a “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w+» 
//  Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
// Match the regex below and capture its match into backreference number 1 «(\w)» 
//  Match a single character that is a “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w» 
// Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b» 
// Match a single character that is NOT a “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «[\W]*» 
//  Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» 
// Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=\1)» 
//  Match the same text that was most recently matched by capturing group number 1 (case insensitive; fail if the group did not participate in the match so far) «\1» 
// Match the same text that was most recently matched by capturing group number 1 (case insensitive; fail if the group did not participate in the match so far) «\1» 
// Match a single character that is a “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w+» 
// Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
0

Regex не будет на самом деле быть в состоянии сказать самый длинный в строке.

Но, используя метод @DeanTaylor, если глобальное совпадение, вы можете сохранить самый длинный на основе длины строки совпадения.

Это небольшое изменение в его регулярном выражении, но оно работает одинаково.

(?:\w*(\w)\W+(?=\1))+\w+

Форматированная:

(?: 
     \w* 
     (\w)   # (1) 
     \W+ 
     (?= \1) 
)+ 
\w+ 
Смежные вопросы