2014-10-07 4 views
2

Я пытаюсь использовать следующий код, чтобы заменить всю строку:Использование replaceAll Java, чтобы заменить всю строку

Код: String a = "Hello"; String b = a.replaceAll("(?s).*", "US"); Выход:

USUS 

Вопрос: Почему строка " США "повторили дважды? Как заменить всю строку с помощью функции replaceAll, используя регулярное выражение?

Зачем мне это нужно: Мне нужно подобрать образцы заметок, указанные в json-файле, с указанными здесь значениями. В этой модели я хотел дать независимость пользователю (json configureurer), чтобы определить шаблон, чтобы можно было заменить всю строку, без необходимости кодирования специальной обработки замены строки.

+2

'. *' Ноль или более раз. Поэтому он заменяет пустую строку 'US', а затем следующую непустую строку с' US' –

+1

, что является мотивацией для * Как заменить всю строку с помощью replaceAll функция, используя регулярное выражение? *, потому что это бесполезная операция. –

+0

'^ [\ s \ S] * $' всегда должен соответствовать всей строке ровно один раз. –

ответ

1

Это потому, что .* может соответствовать пустой строке. так что первый матч все строки (от начала), а второе пустая строка (от последней позиции строки после последнего символа)

Вы можете избежать этого, используя + квантор вместо *. Но он не заменит пустую строку.

+1

'^ [\ s \ S] * $' всегда должен соответствовать всей строке ровно один раз. –

+0

@JanDvorak: действительно, если вы включите конец привязки строки, последняя позиция в строке сопоставляется. –

3

Это связано с тем, как класс Matcher обрабатывает шаблоны, которые могут соответствовать пустой строке. replaceAll метод String определяются работать таким же образом, как replaceAll метод Matcher, который работает следующим образом:

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

Когда сличитель пытается найти шаблон, если подпоследовательности в источнике является пустой строкой, сличитель возвращает пустую строку, а затем натыкается на текущий индекс 1, так что он не возвращает бесконечный цикл пустых строк. Так вот как он действует на "Hello":

1) Соединитель ищет .*. Поскольку это жадное совпадение, совпадающее с максимально возможным количеством символов, оно найдет подстроку "Hello" и использует это, заменив ее на "US". Текущий индекс затем позиционируется после 'o'.

2) Соединитель ищет .* еще раз. Поскольку он находится в конце ввода, но шаблону разрешено сопоставлять пустую строку, он соответствует пустой строке и заменяет ее другим "US". Но затем он подхватывает текущий индекс, который теперь находится в позиции за концом источника.

3) Соединитель снова ищет .*, но поскольку текущий указатель находится за концом источника, он ничего не найдет.

Чтобы узнать, как это работает, попробуйте использовать ".*?" как шаблон.Теперь совпадение будет всегда использовать пустую строку, потому что ? сообщает ей использовать самую короткую строку. Он также увеличивает текущий индекс на 1 каждый раз, когда находит пустую строку. Результат:

a.replaceAll("(?s).*?", ".-") //returns 
".-H.-e.-l.-l.-o.-" 

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

Мораль: будьте очень осторожны с шаблонами, которые могут соответствовать пустым строкам.

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

if ("".matches(inputPattern)) { 
    // ??? 
} 

Я не уверен, что вы с ним сделаете. Возможно, это всегда так, если это правда, ваш replaceAll добавит дополнительно US в конце, и вы можете безопасно удалить его. Или, может быть, вы можете просто попросить их попробовать другой шаблон.

PPS. Я не уверен, где это поведение матчи (т. Е. Увеличение текущего индекса на 1, когда совпадение является пустой строкой) документировано. Я не видел этого в javaadoc Matcher. Я полагаю, это означает, что будущая версия JRE может вести себя по-другому, хотя это кажется маловероятным.

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