2013-11-19 1 views
2

Я пытаюсь получить строки с кавычками, используя regexp.Java regexp in matcher input

String regexp = "('([^\\\\']+|\\\\([btnfr\"'\\\\]|[0-3]?[0-7]{1,2}|u[0-9a-fA-F]{4}))*'|\"([^\\\\\"]+|\\\\([btnfr\"'\\\\]|[0-3]?[0-7]{1,2}|u[0-9a-fA-F]{4}))*\")"; 
Pattern p = Pattern.compile(regexp); 
Matcher m = p.matcher(source); 
while (m.find()) { 
    String newElement = m.group(1); 
    //... 
} 

Он хорошо работает, но если исходный текст содержит

' onkeyup="this.value = this.value.replace (/\D/, \'\')">'

программа переходит в вечный цикл.

Как правильно получить эту строку?

К примеру, у меня есть текст (PHP код):

'qty'=>'<input type="text" maxlength="3" class="qty_text" id='.$key.' value =' 

Результат должен быть

'qty' 
'<input type="text" maxlength="3" class="qty_text" id=' 
' value =' 
+1

Не уверен, что я понимаю, лет ур цели здесь. Не могли бы вы привести несколько примеров ввода -> вывода? – Mena

+0

@Mena, добавленный пример – s0ph1e

ответ

0

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

"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*" 

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

'[^'\\\r\n]*(?:\\.[^'\\\r\n]*)*' 

Он использует Фридл в «развернутый петля "для максимальной эффективности.Вот код Java для него, как генерируется RegexBuddy 4:

Pattern regex = Pattern.compile(
    "\"[^\"\\\\\r\n]*(?:\\\\.[^\"\\\\\r\n]*)*\"|'[^'\\\\\r\n]*(?:\\\\.[^'\\\\\r\n]*)*'" 
); 
+0

Кажется, что вы работаете правильно. Большое спасибо. – s0ph1e

0

Может быть, я неправильно понять принцип, но это выглядит довольно тривиально теперь, когда вы добавили пример.

Рассмотрим это, например:

String input = "'qty'=>'<input type=\"text\" maxlength=\"3\" class=\"qty_text\" id='.$key.' value ='"; 
String otherInput = "' onkeyup=\"this.value = this.value.replace (/\\D/, \'\')\">'"; 
// matching anything starting with single quote and ending with single quote 
// included, reluctant quantified 
Pattern p = Pattern.compile("'.+?'"); 
Matcher m = p.matcher(input); 
while (m.find()) { 
    System.out.println(m.group()); 
} 
m = p.matcher(otherInput); 
System.out.println(); 
while (m.find()) { 
    System.out.println(m.group()); 
} 

Выход:

'qty' 
'<input type="text" maxlength="3" class="qty_text" id=' 
' value =' 

' onkeyup="this.value = this.value.replace (/\D/, ' 
')">' 

Смотрите Java Patterndocumentation для более подробного объяснения.

+0

''. *? ''Приведет к усеченному соответствию для строковых констант с одной кавычкой, которые содержат экранированную одиночную кавычку. – pobrelkey

+0

@pobrelkey ​​ok. Ваша точка? – Mena

+0

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

0

Группы символов, которые не соответствуют ни обратной косой чертой, ни кавычкам, не должны сопровождаться +. Удалите + es, чтобы исправить зависание (которое было вызвано catastrophic backtracking).

Кроме того, ваше исходное регулярное выражение не распознало \D как допустимый обратный слэш - поэтому константа строки в тестовом входе, содержащем \D, не была сопоставлена. Если вы сделаете правила своего регулярного выражения более либеральными, чтобы распознать любого персонажа сразу после обратного слэша как части константы строки, он будет вести себя так, как вы ожидаете.

"('([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\")" 
+0

Я пытаюсь удалить '+' es, но из исходной строки '' qty '=>' ''Я получил результат' [' qty ',' ']', но последнее совпадение должно быть '' onkeyup = "this.value = this.value.replace (/ \ D /, \ ' \ ') ">'' – s0ph1e

+0

Это потому, что в исходном регулярном выражении есть ошибка (он считает '\ D' недействительным). Я обновил свой ответ. – pobrelkey

0

Вы можете сделать все это в одной строке с помощью split() с правом регулярного выражения:

String[] array = source.replaceAll("^[^']+", "").split("(?<!\\G.)(?<=').*?(?='|$)"); 

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

  • ограничитель обернут чет/нечет цитаты, но не может содержать кавычки, потому что split()истребляет разделитель, так что заглянуть за (?<=') и смотреть вперед (?=') (которые, не потребляя) используется для сопоставления кавычки вместо буквальнога цитаты в регулярном выражении
  • неохотно матч .*? для символов между кавычками обеспечивают проведение что он останавливается на следующую цитате (вместо сопоставления до последней котировки)
  • я добавил альтернативный матч для завершения ввода карапуза он смотреть вперед (?='|$) в случае нет задней близко котировки
  • И экономить лучший для последнего , регулярное выражение, которое является ключом к тому, чтобы все это работало, - это отрицательный внешний вид (?<!\\G.), что означает «не совпадают» в конце предыдущего совпадения "и гарантирует, что следующий матч продвинется к концу предыдущего разделителя, без которого вы получите только символы кавычек в вашем массиве. \G соответствует концу предыдущего совпадения, но также соответствует началу ввода для первого совпадения, поэтому он довольно аккуратно обрабатывает не совпадение по первой кавычки - таким образом делая разделитель завернут в четную/нечетную цитату вместо нечетного/даже, как это было бы иначе.
  • Для удовлетворения первого символа на входе не является котировкой, вы должны сдирать ведущие символы перед расщеплением - вот почему replaceAll() нужен

Вот некоторый тестовый код с помощью ввода пробы:

String source = "'qty'=>'<input type=\"text\" maxlength=\"3\" class=\"qty_text\" id='.$key.' value ='"; 
String[] array = source.replaceAll("^[^']+", "").split("(?<!\\G.)(?<=').*?(?='|$)"); 
System.out.println(Arrays.toString(array)); 

Выход:

['qty', '<input type="text" maxlength="3" class="qty_text" id=', ' value ='] 
+0

Спасибо за подробное объяснение. Для моего примера это работает. Я тестировал его с помощью '$ cart = $ this-> session-> userdata ('cart'); $ this-> load-> view ('footer'); 'Я ожидал результата' ['cart', 'footer'] '. Но я получил результат: $ cart = $ this-> session-> userdata ('cart'); $ this-> load-> view ('footer'); ' – s0ph1e

+0

Вы прочитали мой весь ответ, особенно во второй половине, касающийся ввода, который не начинается с цитаты? Мой код работает отлично: он дает желаемый результат. Чтобы было проще, я отредактировал свой ответ, чтобы предположить, что ввод не начинается с цитаты. – Bohemian

+0

Я читал его дважды (или, может быть, больше). Извините, я сделал ошибку в 1-м комментарии. Ваш код работает нормально, но не работает, если вход содержит '\ n'. Когда 'String source = '$ cart = $ this-> session-> userdata (' cart '); \ n $ this-> load-> view (' footer ');"; 'result was' [' cart ') ; $ this-> load-> view (',');] '. Я исправил его с помощью 'String [] array = source.replaceAll ("^[^ '] + | [\\ r \\ n] "," ") .split (" (? s0ph1e

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

  • Нет связанных вопросов^_^