2015-06-19 3 views
1

Можно ли вычесть символы в обратной ссылке Java regex из класса символов?Вычитание символов в обратной ссылке из класса символов в java.util.regex.Pattern

например, я хочу использовать String#matches(regex), чтобы соответствовать либо:

  1. любой группы символов, которые являются [a-z'], которые заключены "

    спичек: "abc'abc"

    Безразлично 't match: "1abc'abc"

    Не соответствует:' abc 'abc'

  2. любой группа символов, которые являются [a-z"], которые заключены '

    спичек: 'а "а'

    Не соответствую: '1abc" ABC'

    Не соответствует: "abc'abc"

следующее регулярное выражение не будет компилироваться, так как [^\1] не поддерживается:

(['"])[a-z'"&&[^\1]]*\1 

Очевидно, что следующий будет работать:

'[a-z"]*'|"[a-z']*" 

Но, этот стиль не особенно разборчивыми, когда a-z заменяется гораздо более сложный класс символов, который должен храниться такой же в каждой стороне "или" условие.

Я знаю, что в Java, я могу просто использовать String конкатенации, как в следующем:

String charClass = "a-z"; 
String regex  = "'[" + charClass + "\"]*'|\"[" + charClass + "']*\""; 

Но, иногда, мне нужно указать регулярное выражение в файле конфигурации, как XML или JSON, и т.д. ., где java-код недоступен.

Я полагаю, что я спрашиваю, почти определенно не представляется возможным, но я понял, что не мешало бы спросить ...

+2

Вы не можете сделать это в классе символов. Однако вместо этого вы можете использовать отрицательный прогноз ('! \ 1) [a-z ']' – nhahtdh

+1

' [az "] '|" [a-z'] "- Предполагаю, вы хотели добавить звездочку после каждой группы символов - т. е. [az "] * вместо просто [az"], которая будет соответствовать только одному символу. – bjfletcher

+0

@bjfletcher Спасибо, что поймал мою опечатку – XDR

ответ

4

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

(['"])(?:(?!\1)[a-z'"])*+\1 
     ^^^^^^ 

(Я также делаю квантификатор притяжательные, так как нет никакой пользы для возвратов здесь)

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

Альтернатива с двумя ветвями в вопросе '[a-z"]*'|"[a-z']*" лучше, так как двигатель проверяет только символ кавычки и проходит через остальные, проверяя, что текущий символ находится в классе символов.

+0

Я всегда думал, что взгляд должен следовать за другим токеном. Is '(['"]) 'токен, который' (?! \ 1) 'следует? – XDR

+1

@XDR: я не совсем понимаю ваш вопрос. Look-ahead утверждает, что из текущей позиции вы не можете найти шаблон внутри поискового запроса, после того, как утверждение будет успешным, вы возобновите сопоставление, прежде чем вводить прогноз. Поэтому фрагмент '(? :(?!\ 1) [a-z '"]) * +' означает: перед тем, как вы сопоставляете следующий символ, убедитесь, что это не то же самое, что и открывающая котировка (которая фиксируется при захвате группы 1). – nhahtdh

1

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

//       | case 1: [a-z'] enclosed by " 
//       |      | OR 
//       |      | case 2: [a-z"] enclosed by ' 
Pattern p = Pattern.compile("(?<=\")([a-z']+)(?=\")|(?<=')([a-z\"]+)(?=')"); 

String[] test = { 
     // will match group 1 (for case 1) 
     "abcd\"efg'h\"ijkl", 
     // will match group 2 (for case 2) 
     "abcd'efg\"h'ijkl", 
}; 
for (String t: test) { 
    Matcher m = p.matcher(t); 
    while (m.find()) { 
     System.out.println(m.group(1)); 
     System.out.println(m.group(2)); 
    } 
} 

Выходные

efg'h 
null 
null 
efg"h 

Примечание

Нет ничего, что помешало бы вам указывать окружающие символы или сам класс символов в другом месте, а затем создать Pattern с неизвестными компонентами во время компиляции.

Что-то в линиях:

// both strings are emulating unknown-value arguments 
String unknownEnclosingCharacter = "\""; 
String unknownCharacterClass = "a-z'"; 
// probably want to catch a PatternSyntaxException here for potential 
// issues with the given arguments 
Pattern p = Pattern.compile(
    String.format(
     "(?<=%1$s)([%2$s]+)(?=%1$s)", 
     unknownEnclosingCharacter, 
     unknownCharacterClass 
    ) 
); 
String[] test = { 
     "abcd\"efg'h\"ijkl", 
     "abcd'efg\"h'ijkl", 
}; 
for (String t: test) { 
    Matcher m = p.matcher(t); 
    while (m.find()) { 
     // note: only main group here 
     System.out.println(m.group()); 
    } 
} 

Выход

efg'h 
+1

@CasimiretHippolyte позвольте мне перефразировать мой ответ :) – Mena

+2

Я пытаюсь избежать «или» условия. См. '' [Az "] * '|" [a-z'] * "' и последующее объяснение в моем вопросе. – XDR

+0

@XDR: Обратите внимание, что этот подход интересен, если вы хотите получить контент между кавычками в одном и том же группы: «[» '] ((? <= \ ") [a-z'] * (? = \") | (? <= ') [az \ "] * (? =')) [ «']'. Использование backreference только замедлит ваш шаблон. См. Также мой другой комментарий. –

Смежные вопросы