RegEx в Java: как бороться с переводом строки - PullRequest
24 голосов
/ 10 августа 2010

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

www.foo.com / Archives / monkeys.htm
Описание веб-сайта Monkey.

www.foo.com / Archives / pigs.txt
Описание веб-сайта Pig.

www.foo.com / Archives / kitty.txt
Описание веб-сайта Kitty.

www.foo.com / Archives / apple.htm
Описание веб-сайта Apple.

Если бы я хотел получить один веб-сайт вместе с его описанием, то это регулярное выражение работает наинструмент тестирования: .*www.*\\s.*Pig.*

Однако, когда я пытаюсь запустить его в своем коде, он не работает.Это выражение правильно?Я попытался заменить "\ s" на "\ n", и это, похоже, не работает до сих пор.

Ответы [ 5 ]

51 голосов
/ 10 августа 2010

Строки, вероятно, разделены \r\n в вашем файле. И \r (возврат каретки), и \n (перевод строки) считаются символами-разделителями строк в регулярных выражениях 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 переводит его в многострочный режим, позволяя ^ и $ совпадать на границах строки.

12 голосов
/ 19 мая 2015

Для дальнейшего использования можно также использовать флаг 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, поэтому вышеупомянутый шаблон может фактически анализировать 'Location' из строк заголовка http, где могут быть другие заголовки до или после целевой строки (не то, что это рекомендуемый способпарсинг заголовков http).

Кроме того, вы можете использовать "? s" внутри шаблона для достижения того же эффекта.

Если вы делаете это, вам может быть лучше использовать Matcher.find().

1 голос
/ 10 августа 2010

попробуйте

([^\r]+\r[^\r])+
1 голос
/ 10 августа 2010

у меня работает:

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's website.\n"
             + "\n"
             + "www.foo.com/Archives/pigs.txt\n"
             + "Description of Pig's website.\n"
             + "\n"
             + "www.foo.com/Archives/kitty.txt\n"
             + "Description of Kitty's website.\n"
             + "\n"
             + "www.foo.com/Archives/apple.htm\n"
             + "Description of Apple's website.\n";
    Matcher m = p.matcher(s);
    if (m.find()) {
      System.out.println(m.group());
    } else {
      System.out.println("ERR: no match");
    }
  }
}

Возможно, проблема была в том, как вы использовали объекты Pattern и Matcher?

0 голосов
/ 10 августа 2010

Эта версия соответствует символам новой строки, которые могут быть либо 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's website.\n"
           + "\r\n"
           + "www.foo.com/Archives/pigs.txt\r\n"
           + "Description of Pig's website.\n"
           + "\n"
           + "www.foo.com/Archives/kitty.txt\n"
           + "Description of Kitty's website.\n"
           + "\n"
           + "www.foo.com/Archives/apple.htm\n"
           + "Description of Apple's 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");
...