2015-01-29 2 views
0

Say есть строка: "first option<option 1/option 2/option 3>second option<option 5/option 6/option 7>selection{aaaaa/bbbbb/ccccc}{eeeeee/fffff/ggggg}other string"Java соответствует регулярному выражению вне Bracks

Теперь я хочу, чтобы получить 3 ArrayList

один для строки внутри "<>":

{"option 1/option 2/option 3", "option 5/option 6/option 7"} 

одна строка внутри "{}":

{"aaaaa/bbbbb/ccccc", "eeeeee/fffff/ggggg"} 

и один для обоих наружных <>/{} и внутри <>/{}:

{"first option", "<option 1/option 2/option 3>", "second option", "<option 5/option 6/option 7>", "selection", "{aaaaa/bbbbb/ccccc}", "other string"}. 

Я понимаю, что я могу получить строку внутри скобок с кодом, как:

String Str = "first option<option 1/option 2/option 3>second option<option 5/option 6/option 7>selection{aaaaa/bbbbb/ccccc}{eeeeee/fffff/ggggg}other string"`; 
    Pattern patt = Pattern.compile("<(.*?)>"); 
    Matcher mtchr_r = patt.matcher(Str); 
    while (mtchr_r.find()){ 
     String ssssssss = mtchr_r.group(); 
    } 

но как соответствовать строки вне скобок? и, кроме того, как получить третий ArrayList в порядке?

+0

Я думаю, что было бы неплохо иметь несколько регулярных выражений. – sashwat

ответ

1

С использованием \G (утверждает, что следующий матч начинается, когда последний матч заканчивается), то можно сделать это в одном передать:

не
\G(?:[^<>{}]++|<(?<pointy>[^<>]++)>|\{(?<curly>[^{}]++)\}) 

простые ломается из выше регулярного выражения:

\G      # Must start from where last match ends 
(?: 
    [^<>{}]++    # Outside {} <> 
    |      # OR 
    <(?<pointy>[^<>]++)> # Capture content inside < > in group named 'pointy' 
    |      # OR 
    \{(?<curly>[^{}]++)\} # Capture content inside < > in group named 'curly' 
) 

Если предположить, что нет <> внутри <> и там нет {} внутри {}, и нет непревзойденного <>{}, регулярное выражение выше должно правильно разбить строку.

Регулярное выражение остановится в первой позиции, где встречается некорректная последовательность, поэтому в приведенном ниже примере кода я уверен, что позиция последнего совпадения находится в конце строки.

Полный пример программы (Java 7, но вы можете удалить именованный захватив группу, чтобы запустить его в предыдущих версиях Java):

import java.util.ArrayList; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 


public class SO28210525 { 
    private static final Pattern re = Pattern.compile("\\G(?:[^<>{}]++|<(?<pointy>[^<>]++)>|\\{(?<curly>[^{}]++)\\})"); 

    public static void main(String[] args) { 
     String input = "first option<option 1/option 2/option 3>second option<option 5/option 6/option 7>selection{aaaaa/bbbbb/ccccc}{eeeeee/fffff/ggggg}other string"; 
     Matcher matcher = re.matcher(input); 

     ArrayList<String> tokens = new ArrayList<String>(); 
     ArrayList<String> curly = new ArrayList<String>(); 
     ArrayList<String> pointy = new ArrayList<String>(); 

     int lastIndex = 0; 

     while (matcher.find()) { 
      tokens.add(matcher.group(0)); 

      String inCurly = matcher.group("curly"); 
      if (inCurly != null) { 
       curly.add(inCurly); 
      } 

      String inPointy = matcher.group("pointy"); 
      if (inPointy != null) { 
       pointy.add(inPointy); 
      } 

      lastIndex = matcher.end(0); 
     } 

     if (lastIndex != input.length()) { 
      System.err.println("Invalid input"); 
     } else { 

      System.out.println(tokens); 
      System.out.println(curly); 
      System.out.println(pointy); 
     } 
    } 

} 

В предыдущей версии Java (6 и ниже), как альтернативой, вы можете использовать метод Matcher.start или Matcher.end, чтобы проверить, захватывает ли группа захвата что-то или нет.

Однако в Java 7 отсутствуют соответствующие методы Matcher.start и Matcher.end для названной группы захвата (доступно только Matcher.group). 2 метода позже добавляются в Java 8.

+0

Я получаю тот же результат, используя 'Pattern.compile (" [^ <> {}] + | <(? [^ <>] +)> | \\ {(? [^ {}] +) \\} ") '. Что делает '\\ G'? – Keppil

+0

@Keppil: принудительно вызывать регулярное выражение, когда вход недействителен. Он, по крайней мере, обеспечивает механизм для обнаружения плохой входной информации, а не просто зажимает ее. – nhahtdh

+0

@ Keppil: Я соглашаюсь с содержимым разделителей + внутри и устанавливаю подходящую группу захвата для захвата содержимого внутри. – nhahtdh

0
(?<=<)[^>]*(?=>)|(?<={)[^}]*(?=}) 

Вы можете использовать это, чтобы получить обе строки внутри <> и {} .Увидь демо.

https://regex101.com/r/pM9yO9/19

Используйте это, чтобы получить все отдельно, включая тех, кто снаружи.

(?<=<)[^>]*(?=>)|(?<={)[^}]*(?=})|[^<>{}]+ 

https://regex101.com/r/pM9yO9/20

1

Один из вариантов будет иметь регулярное выражение, которое соответствует всем случаям, например, (<[^>]*>)|(\{[^}]*\})|([^{<]*) (в Java вы должны избежать \ с)

Однако это не позволяет различать тип матча (<...>, {...} или остального текста) найдено. Так что, вероятно, будет лучше иметь 3 регулярные выражения, как предложено в комментариях к вашему вопросу:

Pattern pattern1 = Pattern.compile("<(.*?)>"); 
Pattern pattern2 = Pattern.compile("\\{(.*?)\\}"); 
Pattern pattern3 = Pattern.compile("(<[^>]*>)|(\\{[^}]*\\})|([^{<]*)"); 

Вы можете просто добавить все матчи в списки.

+0

Не могли бы вы объяснить, почему '([^ {<] *)' в pattern3 соответствует внешним символам '<>' и '{}'? Благодарю. – TRX

+0

'[]' определяет набор символов для соответствия. '^' внутри этих средств «Сопоставьте что-нибудь, кроме ...». Таким образом, оно совпадает с количеством символов, которое может быть не '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'и обозначающее начало другого типа группы. – icke

+0

Итак, почему '([^ {<] *)' не соответствует чему-либо внутри '<>'? – TRX

1

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

String Str = "first option<option 1/option 2/option 3>second option<option 5/option 6/option 7>selection{aaaaa/bbbbb/ccccc}{eeeeee/fffff/ggggg}other string"; 
     Pattern inside = Pattern.compile("<(.*?)>"); 
     Pattern insideBrackets = Pattern.compile("\\{(.+?)\\}"); 
     Pattern inAndOutside = Pattern.compile("(<[^>]*>)|(\\{[^}]*\\})|([^{<]*)"); 
     Matcher matcher1 = inside.matcher(Str); 
     Matcher matcher2 = insideBrackets.matcher(Str); 
     Matcher matcher3 = inAndOutside.matcher(Str); 
     ArrayList<String> array1 = new ArrayList<>(); 
     ArrayList<String> array2 = new ArrayList<>(); 
     ArrayList<String> array3 = new ArrayList<>(); 
     boolean found = false; 
     while (matcher1.find()) { 
      array1.add(matcher1.group(1)); 
      System.out.println(matcher1.group(1)); 
      found = true; 
     } 

     while (matcher2.find()) { 
      array2.add(matcher2.group(1)); 
      System.out.println(matcher2.group(1)); 
      found = true; 
     } 

     while (matcher3.find()) { 
      array3.add(matcher3.group(1)); 
      System.out.println(matcher3.group(1)); 
      found = true; 
     } 

     if (!found) { 
      System.out.println("No match found"); 
     } 
    } 
+0

Не могли бы вы объяснить, почему '([^ {<] *)' в 'inAndOutside' соответствует вне' <...> 'и' {...} '? Благодарю. – TRX