RegEx в Java: как бороться с новой линией
В настоящее время я пытаюсь научиться использовать регулярные выражения, поэтому, пожалуйста, не забывайте мой простой вопрос. Например, скажем, у меня есть входной файл, содержащий кучу ссылок, разделенных символом новой строки:
www.foo.com/Archives/monkeys.htm
Описание сайта Monkey.
www.foo.com/Archives/pigs.txt
Описание сайта Свинья.
www.foo.com/Archives/kitty.txt
Описание сайта Китти.
www.foo.com/Archives/apple.htm
Описание веб-сайта Apple.
Если бы я хотел получить один сайт вместе с его описанием, это регулярное выражение, похоже, работает с инструментом тестирования: .*www.*\\s.*Pig.*
Однако, когда я пытаюсь запустить его в своем коде, он не работает. Правильно ли это выражение? Я попытался заменить "\ s" на "\n", и он, похоже, не работает.
Ответы
Ответ 1
Линии, вероятно, разделены \r\n
в вашем файле. Оба \r
(возврат каретки) и \n
(linefeed) считаются символами разделителя строк в регулярных выражениях Java, а метасимвол .
не соответствует ни одному из них. \s
будет соответствовать этим символам, поэтому он потребляет \r
, но оставляет .*
в соответствии с \n
, который терпит неудачу. Возможно, ваш тестер использовал только \n
для разделения строк, которые были использованы \s
.
Если я прав, изменение \s
на \s+
или [\r\n]+
должно заставить его работать. Это, вероятно, все, что вам нужно сделать в этом случае, но иногда вам приходится сопоставлять ровно один разделитель строк или, по крайней мере, отслеживать, сколько вы соответствуете. В этом случае вам понадобится регулярное выражение, которое соответствует точно одному из трех наиболее распространенных типов разделителей строк: \r\n
(Windows/DOS), \n
(Unix/Linus/OSX) и \r
(более старые компьютеры Mac). Любой из них будет делать:
\r\n|[\r\n]
\r\n|\n|\r
Обновление:. По состоянию на Java 8 у нас есть еще один вариант, \r
. Он соответствует любому разделителю строк, включая не только \r\n
, но и несколько других, как определено стандартом Unicode. Это эквивалентно этому:
\r\n|[\n\x0B\x0C\r\u0085\u2028\u2029]
Здесь вы можете использовать его:
(?im)^.*www.*\R.*Pig.*$
Опция i
делает ее нечувствительной к регистру, а m
помещает ее в многострочный режим, позволяя ^
и $
соответствовать границам строк.
Ответ 2
Для справок в будущем можно также использовать флаг Pattern.DOTALL для "." для соответствия даже \r или\n.
Пример:
Скажем, мы разбираем одну строку строк заголовка http, подобных этой (каждая строка заканчивается на \r\n)
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: SAMEORIGIN
Location: http://localhost:8080/blah.htm
Content-Length: 0
Этот шаблон:
final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL);
Можно проанализировать значение местоположения с помощью команды "matcher.group(1)".
"." в приведенном выше шаблоне будут соответствовать \r и\n, поэтому приведенный выше шаблон может фактически анализировать "местоположение" из строк заголовка http, где могут быть другие заголовки до или после целевой строки (не это рекомендуется для разобрать заголовки http).
Кроме того, вы можете использовать "? s" внутри шаблона для достижения того же эффекта.
Если вы делаете это, вам может быть лучше использовать Matcher.find().
Ответ 3
попробуйте это
([^\r]+\r[^\r])+
Ответ 4
Работает для меня:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Foo {
public static void main(String args[]) {
Pattern p = Pattern.compile(".*www.*\\s.*Pig.*");
String s = "www.foo.com/Archives/monkeys.htm\n"
+ "Description of Monkey website.\n"
+ "\n"
+ "www.foo.com/Archives/pigs.txt\n"
+ "Description of Pig website.\n"
+ "\n"
+ "www.foo.com/Archives/kitty.txt\n"
+ "Description of Kitty website.\n"
+ "\n"
+ "www.foo.com/Archives/apple.htm\n"
+ "Description of Apple website.\n";
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println(m.group());
} else {
System.out.println("ERR: no match");
}
}
}
Возможно, проблема заключалась в том, как вы использовали объекты Pattern и Matcher?
Ответ 5
Эта версия соответствует новым строкам, которые могут быть либо Windows (\ r\n), либо Unix (\n)
Pattern p = Pattern.compile("(www.*)((\r\n)|(\n))(.*Pig.*)");
String s = "www.foo.com/Archives/monkeys.htm\n"
+ "Description of Monkey website.\n"
+ "\r\n"
+ "www.foo.com/Archives/pigs.txt\r\n"
+ "Description of Pig website.\n"
+ "\n"
+ "www.foo.com/Archives/kitty.txt\n"
+ "Description of Kitty website.\n"
+ "\n"
+ "www.foo.com/Archives/apple.htm\n"
+ "Description of Apple website.\n";
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println("found: "+m.group());
System.out.println("website: "+m.group(1));
System.out.println("description: "+m.group(5));
}
System.out.println("done");