Question

J'ai un fichier contenant plusieurs lignes similaires à:

Name: Peter
Address: St. Serrano número 12, España
Country: Spain

Et je dois extraire l'adresse en utilisant une expression régulière, en tenant compte du fait qu'il peut contenir des points, des caractères spéciaux (ñ, ç), AEIOU ...

Le code actuel fonctionne, mais il semble assez laid:.

Pattern p = Pattern.compile("^(.+?)Address: ([a-zA-Z0-9ñÑçÇáéíóú., ]+)(.+?)$",
                            Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = p.matcher(content);
if (m.matches()) { ... }

Edit: Le champ d'adresse peut également être divisée en plusieurs lignes

Name: Peter
Address: St. Serrano número 12,   
Madrid
España
Country: Spain

Edit:. Je ne peux pas utiliser un objet Propriétés ou un analyseur YAML, que le fichier contient d'autres types d'informations aussi

Était-ce utile?

La solution

Je ne sais pas les objets regex Java qui fonctionnent bien, mais quelque chose comme ce modèle le ferai:

^Address:\s*((?:(?!^\w+:).)+)$

supposant que les modes multilignes et dotall sont allumés.

correspondra à une ligne commençant par adresse, suivi de quoi que ce soit jusqu'à ce qu'un saut de ligne et un seul mot suivi par deux points.

Si vous connaissez le champ suivant doit être « Pays », vous pouvez simplifier un peu:

^Address:\s*((?:(?!^Country:).)+)$

L'astuce consiste dans l'affirmation d'anticipation dans le groupe répétitif. '(?!Pays:).' correspondra à tout sauf le début de la chaîne « Pays: », donc nous collons juste entre parenthèses (non capturé: ...). et de quantifier avec +, puis groupe tout cela entre parenthèses normales de capture

Autres conseils

Vous pouvez regarder dans la classe Properties au lieu de regex. Il vous fournit les moyens de gérer des fichiers texte ou XML simples pour représenter des paires clé-valeur.

Vous pouvez lire dans votre fichier exemple, puis obtenir les valeurs comme si après le chargement d'un objet Properties:

Properties properties = new Properties();
properties.load(/* InputStream of your file */);

Assert.assertEquals("Peter", properties.getProperty("Name"));
Assert.assertEquals("St. Serrano número 12, España", properties.getProperty("Address"));
Assert.assertEquals("Spain", properties.getProperty("Country"));

En supposant « contenu » est une chaîne contenant le contenu du fichier, votre principal problème est que vous utilisez matches() où vous devez utiliser find().

Pattern p = Pattern.compile("^Address:\\s*(.*)$", Pattern.MULTILINE);
Matcher m = p.matcher(content);
if ( m.find() )
{
  ...
}

Il semble y avoir une certaine confusion dans d'autres réponses sur les modes multline et dotall. MULTILINE est ce qui permet de les ancres ^ et $ correspondent au début et à la fin, respectivement, d'une ligne logique. DOTALL laisse le point (période, arrêt complet, peu importe) ligne de correspondance des caractères de séparation comme \n (saut de ligne) et \r (retour chariot). Cette regex doit utiliser le mode multilignes et ne doit pas utilisez le mode dotall.

Je ne veux pas être un bâton dans la boue, mais avez-vous d'utiliser une expression régulière? Pourquoi ne pas épargner votre moi futur (ou d'autres) le mal de tête et à faire:

String line = reader.readLine();
while(line != null)
{
    line = line.trim();
    if(line.startsWith("Address: "))
    {
        return line.substr("Address: ".length()).trim();
    }
    line = reader.readLine();
}
return null;

Bien sûr, cela peut être un peu paramétrés aussi bien et mis dans une méthode.

Dans le cas contraire, je les secondes propriétés ou suggestions JYaml.

Pas une personne Java, mais ne serait pas un travail de "Address: (.*)$"?

Edit: Sans Pattern.MULTILINE | l'option Pattern.DOTALL il doit correspondre uniquement sur cette ligne.

Peut-il contenir une nouvelle ligne? Si elle ne peut pas contenir un saut de ligne, vous n'avez pas besoin d'utiliser le modificateur multiligne, et peut faire à la place

Pattern p = Pattern.compile("^Address: (.*)$");

Si elle peut, une alternative que je peux penser est

Pattern p = Pattern.compile("Address: (.*)\nCountry", Pattern.MULTILINE);

Sans DOTALL, le point ne correspond pas à une nouvelle ligne, donc, vous pouvez le spécifier dans l'expression rationnelle, vous permettant de faire ce que vous avez demandé au sujet.

Vous devez absolument vérifier YAML .

Vous pouvez essayer JYaml .

Le meilleur de tout ce qu'elle a mises en œuvre dans de nombreuses langues.

ps j'ai essayé le texte d'exemple dans YAML :: XS , et il fonctionne parfaitement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top