web-dev-qa-db-fra.com

RegEx en Java: comment traiter newline

J'essaie actuellement d'apprendre à utiliser des expressions régulières, alors n'hésitez pas à poser une question simple. Par exemple, disons que j'ai un fichier d'entrée contenant un tas de liens séparés par une nouvelle ligne:

www.foo.com/Archives/monkeys.htm 
Description du site web de Monkey.

www.foo.com/Archives/pigs.txt 
Description du site web de Pig.

www.foo.com/Archives/kitty.txt 
Description du site de Kitty.

www.foo.com/Archives/Apple.htm 
Description du site Web d'Apple.

Si je voulais obtenir un site Web avec sa description, cette expression régulière semble fonctionner sur un outil de test: .*www.*\\s.*Pig.*

Cependant, lorsque j'essaie de l'exécuter dans mon code, cela ne semble pas fonctionner. Cette expression est-elle correcte? J'ai essayé de remplacer "\ s" par "\ n" et cela ne semble toujours pas fonctionner.

20
user415663

Les lignes sont probablement séparées par \r\n dans votre fichier. \r (retour chariot) et \n (saut de ligne) sont considérés comme des séparateurs de ligne dans les expressions rationnelles Java, et le métacaractère . ne correspond à aucun d'entre eux. \s correspond à ces caractères, donc il consomme le \r, mais il reste .* pour correspondre au \n, qui échoue. Votre testeur a probablement utilisé uniquement \n pour séparer les lignes, qui ont été consommées par \s.

Si j'ai raison, changer le \s en \s+ ou [\r\n]+ devrait le faire fonctionner. C’est probablement tout ce que vous avez à faire dans ce cas, mais vous devez parfois faire correspondre exactement un séparateur de ligne ou au moins garder une trace du nombre de correspondances. Dans ce cas, vous avez besoin d'une expression rationnelle qui corresponde exactement à l'un des trois types de séparateurs de lignes les plus courants: \r\n (Windows/DOS), \n (Unix/Linus/OSX) et \r (Mac plus anciens). L'une ou l'autre fera l'affaire:

\r\n|[\r\n]

\r\n|\n|\r

Update: À partir de Java 8, nous avons une autre option, \R . Il correspond à n’importe quel séparateur de ligne, pas seulement \r\n, mais à plusieurs autres comme défini par le norme Unicode . C'est équivalent à ceci:

\r\n|[\n\x0B\x0C\r\u0085\u2028\u2029]

Voici comment vous pourriez l'utiliser:

(?im)^.*www.*\R.*Pig.*$

L'option i le rend insensible à la casse et le m le met en mode multiligne, permettant à ^ et $ de correspondre aux limites de la ligne.

43
Alan Moore

Pour référence future, l’on peut également utiliser le drapeau Pattern.DOTALL pour "." faire correspondre même\r ou\n. 

Exemple:

Dites que nous analysons une seule chaîne de lignes d’en-tête http comme ceci (chaque ligne se termine par\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

Ce motif:

final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL);

Peut analyser la valeur d'emplacement en utilisant "matcher.group (1)".

Le "." dans le modèle ci-dessus correspondra à\r et\n, le modèle ci-dessus peut donc analyser le "Lieu" à partir des lignes d'en-tête http, où il pourrait y avoir d'autres en-têtes avant ou après la ligne cible analyser les en-têtes http).

En outre, vous pouvez utiliser "? S" à l'intérieur du motif pour obtenir le même effet.

Si vous faites cela, vous feriez peut-être mieux d'utiliser Matcher.find ().

10
javaPhobic

essaye ça

([^\r]+\r[^\r])+
1
user414661

Travaille pour moi:

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");
    }
  }
}

Le problème provenait peut-être de la manière dont vous utilisiez les objets Pattern et Matcher?

0
maerics

Cette version correspond aux nouvelles lignes pouvant être Windows (\ r\n) ou 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");
0
Gary