4
votes

Une expression régulière pour faire correspondre un groupe suivi d'un caractère spécifique

Je dois donc faire correspondre ce qui suit:

1.2.
3.4.5.
5.6.7.10

((\ d +) \. (\ d +) \. ((\ d +) \.) *) code> fera très bien pour la toute première ligne, mais le problème est: il peut y avoir plusieurs lignes: peut-être une ou plusieurs.

\ n n'apparaîtra que si il y a plus d'une ligne.

En version chaîne, je l'obtiens comme ceci: "1.2.\n3.4.5.\n1.2."

Donc mon problème est: s'il n'y a qu'une seule ligne, \ n n'a pas besoin d'être à la fin, mais s'il y a plus d'une ligne, \ n a besoin être là à la fin de chaque ligne sauf la toute dernière.


3 commentaires

Il manque une parenthèse fermante ((\ d +) \. (\ D +) \. ((\ D +) \.) * où devrait-il être? Ou le premier ne devrait-il pas être là?


Votre regex ne correspond pas complètement à la dernière ligne? vous voulez faire correspondre la ligne complète ou non?


Veuillez ajouter d'autres exemples qui devraient correspondre et qui ne devraient pas.


4 Réponses :


2
votes

Voici le modèle que je suggère:

^                   from the start of the string
\d+                 match a number
(?:\.\d+)*          followed by dot, and another number, zero or more times
\.?                 followed by an optional trailing dot
(?:\n               followed by a newline
\d+(?:\.\d+)*\.?)*  and another path sequence, zero or more times
$                   end of the string

Démo

Voici une brève explication du modèle:

^\d+(?:\.\d+)*\.?(?:\n\d+(?:\.\d+)*\.?)*$


2 commentaires

Cela correspond à plus que ce qui est requis. Cela correspondrait à 1. et 1. \ n1. \ N1. .


@ArslanAli Oui, et cela est en fait suggéré par vos propres exemples de données.



0
votes

(\ d + \. *) + \ n * correspondra au texte que vous avez fourni. Si vous devez vous assurer que la dernière ligne se termine également par un . alors (\ d + \.) + \ N * fonctionnera.


3 commentaires

Cette expression régulière correspond également à ces types de chaînes 1 ... 2 ... 3 ... .


@ElChiniNet, c'est vrai. Voici une version modifiée qui ne correspondra pas à plusieurs . dans une ligne: ((\ d + \.?) + \ N?) +


Salut, le problème avec ce second est qu'il correspondra à quelque chose de similaire à 0123456789 .



2
votes

Vous pouvez vérifier s'il y a une nouvelle ligne à la fin en utilisant une anticipation positive (?=.*\n):

^(?:\d+\.\d+\.(?:\d+\.)*(?=.*\n\d+\.\d+\.)|\d+\.\d+\.(?:\d+\.)*(?!.*\n))

Voir un démo regex

Vous pouvez utiliser une alternance pour faire correspondre l'un ou l'autre lorsque sur la ligne suivante il y a le même modèle suivant, ou correspondre au modèle lorsqu'il n'est pas suivi d'une nouvelle ligne.

(?=.*\n)(\d+)\.(\d+)\.((\d+)\.)*

Démo Regex

  • ^ Début de chaîne
  • (?: Groupe sans capture
    • \ d + \. \ d + \. Correspond à 2 fois un chiffre et un point
    • (?: \ d + \.) * Répétez plus de 0 fois avec plus de 1 chiffre et un point
    • (? =. * \ n \ d + \. \ d + \.) Lookahead positif, affirmer ce qui suit une nouvelle ligne commençant par le motif
    • | Ou
    • \ d + \. \ d + \. Correspond à 2 fois un chiffre et un point
    • (?: \ d + \.) * Répétez plus de 0 fois avec plus de 1 chiffre et un point
    • * (?!. * \ n) Lookahead négatif, affirmer que ce qui suit n'est pas une nouvelle ligne
  • ) Fermer le groupe non capturant


2 commentaires

Il ne correspond pas à 1.2. . S'il n'y a qu'une seule ligne, il n'y aura pas de \ n .


@ArslanAli Serait-ce un meilleur match? démo 3 lignes et démo 1 ligne



0
votes

La plupart des langages de programmation proposent l'indicateur m . Quel est le modificateur multiligne . L'activation de cette option permettrait à $ de correspondre à la fin des lignes et à la fin de la chaîne.

La solution ci-dessous ajoute uniquement le $ à votre expression régulière actuelle et définit le m drapeau. Cela peut varier en fonction de votre langage de programmation.

var text = "1.2.\n3.4.5.\n1.2.\n12.34.56.78.123.\nthis 1.2. shouldn't hit",
    regex = /(\d+\.){2,}$/gm;

/* Slice is used to drop the dot at the end, otherwise resulting in
 * an empty string on split.
 *
 *     "1.2.3.".split(".")   //=> ["1", "2", "3", ""]
 *     "1.2.3.".slice(0, -1) //=> "1.2.3"
 *     "1.2.3".split(".")    //=> ["1", "2", "3"]
 */
console.log(
  text.match(regex)
      .map(match => match.slice(0, -1).split("."))
);

Vous pouvez simplifier l'expression régulière en /(\d+\.){2,}$/gm , puis diviser la correspondance complète en fonction du caractère point pour obtenir toutes les différentes Nombres. J'ai donné un exemple JavaScript ci-dessous, mais obtenir une sous-chaîne et diviser une chaîne sont des opérations assez basiques dans la plupart des langues.

var text = "1.2.\n3.4.5.\n1.2.\n12.34.56.78.123.\nthis 1.2. shouldn't hit",
    regex = /((\d+)\.(\d+)\.((\d+)\.)*)$/gm,
    match;


while (match = regex.exec(text)) {
  console.log(match);
}

Pour plus d'informations sur les indicateurs / modificateurs d'expression régulière, consultez: Expression régulière Référence: Modificateurs de mode


0 commentaires