7
votes

Plusieurs matchs imbriqués dans une expression régulière JavaScript

essayer d'écrire une expression régulière pour correspondre aux modèles de code à barres GS1 ( https: //fr.wikipedia. Org / wiki / GS1-128 ), contenant 2 ou plusieurs de ces modèles ayant un identifiant suivi d'un certain nombre de caractères de données.

J'ai besoin de quelque chose que correspond à ce code à barres car il contient 2 des motifs d'identifiant et de données: p>

Lisible humain avec les identificateurs de Parens: (01) 12345678901234 (17) 501200 P>

Données réelles: 0112345678901234177501200 CODE> P>

Mais doit correspondre non à ce code à barres lorsqu'il n'y a qu'un seul motif dans: P >

Lisible humain: (01) 12345678901234 P>

Données réelles: 0112345678901234 CODE> P>

Il semble que ce qui suit devrait fonctionner: p>

p>

// Remove {2,} and it will return the first match
var regex = /(?:01(\d{14})|10([^\x1D]{6,20})|11(\d{6})|17(\d{6}))/g;
var str = "011234567890123417501200";

console.log(str.replace(regex, "$4"));
// matches 501200
console.log(str.replace(regex, "$1"));
// matches 12345678901234
// but then the problem is it would also match single identifiers such as
var str2 = "0112345678901234";
console.log(str2.replace(regex, "$1"));
 


10 commentaires

Quel est le match attendu?


J'ai modifié la question pour illustrer ce que sont les matchs. Merci!


Est 0112345678901234177501200 chaîne ou numéro? Sont 01 et 17 constantes?


01123456789012341750120000 Une chaîne renvoyée à partir du scanner de code à barres et de 01 et 17 sont des identifiants, comme indiqué dans la spécification GS1-128 indiquant ce que le type de données sera et le nombre de caractères qu'il contiendra.


Avez-vous essayé de créer un objet dans lequel les noms de propriétés sont la séquence de code et les valeurs le .length de la chaîne attendue adjacente à AI? Ensuite, vérifiez la chaîne pour paires de touches, de valeur de valeur?


Je ne suis pas sûr de suivre ... Dites-vous de ne pas utiliser regex? Je dois utiliser Regex car il provient d'un paramètre de configuration différent par client dans notre base de données.


var correspondances = {"01": / 01 (? = \ d {14}) /, "17": 17 (? = \ d {6}) /} , correspond à chaque propriété, Valeur ou retour faux . Vous pouvez également utiliser une fonction et .Every () qui retourne true ou false pour passer [correspondances] , Itération de biens et de valeurs pour créer REGEXP () des paramètres passés. Pouvez-vous décrire un motif spécifique? Quelles sont ou parties de regexp ?


C'est-à-dire, cassez le REGEXP dans les portions où vous êtes certain que le code correct Boolean est renvoyé, au lieu d'essayer d'utiliser un seul Regexp var fn = fonction (str, re) {return re.Every (fonction (regex) {retour regex.test (str)})}; fn (str, [/ 01 (? = \ d {14}) /, / 17 (? = \ d {6}) /])


Oui, c'est ce que j'essayais de faire dans la dernière partie de mon poste mis à jour, où je mentionne que tout fonctionne correctement si je viens de supprimer le {2,} , mais j'essaie de comprendre Pourquoi. Il semble que cela reconnaisse qu'il y a deux matches, car il retournera le deuxième match (4 $), mais pour une raison quelconque, il reconnaît qu'il a deux matchs, mais cela ne retournera pas le premier des deux allumettes.


Est le problème : ? Examiner REGEXP , est-ce qu'il n'y a qu'un seul groupe de capture? Vous pouvez obtenir des correspondances une à la fois en utilisant .match ()


3 Réponses :


0
votes

Mise à jour

1st exemple strong> p>

Exemple avec 1 $ $ $ 3 $ 3 $ 4 Je ne sais pas pourquoi dans matrice :) p>

Mais vous voyez 1 $ - > abc 2 $ -> DEF $ 3 -> GHI $ 4 -> JKL P>

P>

var regex = /(?:01(\d{14})|10(\x1D{6,20})|11(\d{6})|17(\d{6})){2,}/g;
var str = "011234567890123417501200";

// test
console.log(str.replace(regex, "$1 1st "));
console.log(str.replace(regex, "$2 2nd "));
console.log(str.replace(regex, "$3 3rd "));
console.log(str.replace(regex, "$4 4th "));


6 commentaires

Merci! Mais le [^ \ x1d] est d'arrêter la correspondance de données s'il existe un caractère de séparateur de groupe invisible comme on le voit ici: Condor.depaul.edu/sjost/lsp121/documents/asci-npr.htm Comment ferais-je annuler ce caractère?


Dans votre dernier exemple, les dernières sorties de la console: 1234567890123417501200 lorsqu'il ne devrait émettre que 12345678901234


C'est pourquoi j'ai dit semble fonctionne :) @jacobh pour nier sans [^] Utilisez \ x il nie la valeur hexagonale


On dirait que vous le mettez à nouveau mis à nouveau. Merci d'enquêter! On dirait que c'est de retour au problème initial, en ce sens qu'il ne renvoie aucun des matchs à l'exception du dernier match.


Vous feriez votre texte plus lisible si vous termineriez des phrases de temps en temps.


"Une barre oblique inverse et échappé dans la zone niée n'a pas de sens" : ce n'est pas vrai: la barre oblique inverse a une signification dans les classes naissées.



3
votes

VOTRE REGEX est logiquement et syntialatiquement pour les expressions ordinaires compatibles Perl-compatibles (PCRE). Le problème que je crois que vous êtes confronté est le fait que JavaScript a des problèmes avec des groupes de capture répétés. C'est pourquoi la regex fonctionne bien une fois que vous avez pris le {2,} code>. En ajoutant le quantificateur, JavaScript sera sûr de revenir uniquement fort> le dernier match.

Ce que je recommanderais, c'est supprimer le quantificateur {2,} code> et ensuite vérifiant par programme. allumettes. Je sais que ce n'est pas idéal pour ceux qui sont de grands fans de regex, mais c'est la vie em>. P>

S'il vous plaît voir l'extrait ci-dessous: p>

p>

var regex = /(?:01(\d{14})|10([^\x1D]{6,20})|11(\d{6})|17(\d{6}))/g;
var str = "011234567890123417501200";

// Check to see if we have at least 2 matches.
var m = str.match(regex);
console.log("Matches list: " + JSON.stringify(m));
if (m.length < 2) {
    console.log("We only received " + m.length + " matches.");
} else {
    console.log("We received " + m.length + " matches.");
    console.log("We have achieved the minimum!");
}

// If we exec the regex, what would we get?
console.log("** Method 1 **");
var n;
while (n = regex.exec(str)) {
    console.log(JSON.stringify(n));
}

// That's not going to work.  Let's try using a second regex.
console.log("** Method 2 **");
var regex2 = /^(\d{2})(\d{6,})$/;
var arr = [];
var obj = {};
for (var i = 0, len = m.length; i < len; i++) {
    arr = m[i].match(regex2);
    obj[arr[1]] = arr[2];
}

console.log(JSON.stringify(obj));

// EOF


3 commentaires

Merci d'avoir confirmé qu'il s'agissait d'un problème spécifique JavaScript! C'est ce que j'espérais ne pas être le cas, mais le seul qui a eu sens à moi avoir vu qu'il fonctionnait correctement dans Ruby, avec l'utilitaire en ligne Ruby Regex: rubular.com connaissez-vous n'importe où qui documente les" problèmes avec des groupes de capture répétés "dans JavaScript?


Je ne connais aucun endroit qui indique explicitement que le moteur JavaScript Regex ne le fait pas correctement; Cependant, différentes langues ont des réputations différentes avec leur respect à des expressions régulières. La réputation de JS n'est pas si bonne. J'ai trouvé cette page ( rexegg.com/regex-javascript.html#critplied) Ce qui explique certains des problèmes courants de JS avec regex et propose une bibliothèque pouvant être utile.


@Grisza Nice! Merci d'avoir partagé.



1
votes

La raison en est que les groupes de capture ne donnent que le dernier match par ce groupe particulier. Imaginez que vous auriez deux codes à barres dans votre séquence qui ont à la fois le même identifiant 01 code> ... maintenant, il devient évident que 1 $ code> ne peut pas se référer aux deux en même temps. Le groupe de capture conserve uniquement la deuxième occurrence.

Un moyen simple, mais pas si élégant, est de supprimer le {2,} code> et répétez plutôt le motif d'expression régulier pour correspondre au second code à barres. séquence. Je pense que vous devez également utiliser le ^ code> (début de l'ancrage de chaîne) pour vous assurer que la correspondance est au début de la chaîne, sinon vous pourriez récupérer un identifiant à mi-chemin d'une séquence non valide. Après le motif d'expression régulier répété, vous devez également ajouter . * Code> si vous souhaitez ignorer tout ce qui suit après la deuxième séquence, et ne vous y retournerez pas lorsque vous utilisez remplacer code> . P>

Enfin, comme vous ne savez pas quel identifiant sera trouvé pour la première et deuxième match, vous devez reproduire 1 $ $ 3 $ 3 $ 4 code> dans votre Remplacer , sachant que l'une de ces quatre sera une chaîne non vide. Idem pour le deuxième match: 5 $ 6 $ 7 $ 8 $ 8 $ code>. P>

Voici le code amélioré appliqué à votre exemple de chaîne: p>

P>

var str = "011234567890123417501200";
var regex = /(?:01(\d{14})|10([^\x1D]{6,20})|11(\d{6})|17(\d{6})|(.))/g;
//              1: ^^^^^^  2: ^^^^^^^^^^^^^  3: ^^^^^  4: ^^^^^ 5:^ (=failure)
var result = [], grp;
while ((grp = regex.exec(str)) && !grp[5]) result.push(grp.slice(1).join(''));

// Consider it a failure when not at least 2 matched.
if (result.length < 2) result = [];
console.log(result);


8 commentaires

Merci d'avoir répondu! J'aime ta pensée, mais je viens de trouver une autre idée, basée partiellement sur votre idée de la dupliquer deux fois deux fois, mais j'ai fait du deuxième groupe un regard sur l'avenir: (?: 01 (\ d {14 }) | 10 ([^ \ x1d] {6,20}) | 11 (\ d {6}) | 17 (\ d {6})) (? = 01 (\ d {14}) | 10 ( [^ x1d] {6,2 0}) | 11 (\ d {6}) | 17 (\ d {6})) et quand il semble que cela semble toujours retourner tous les allumettes! Merci pour la réponse et inspiration!


Mais alors le remplacer que vous avez utilisé donnera un résultat qui comprendra plus que la correspondance.


Vous avez raison, oui, qui semble donner plus que ce qui est nécessaire pour 1 $, bien que avec 4 $, cela fonctionne correctement ... étrange. Darn, si proche! Merci!


Le problème principal que je vois avec votre solution d'origine est que cela ne fonctionne que s'il ya deux matchs dans le code à barres, qui fonctionne pour mon exemple donné, mais en réalité, il peut y avoir plus de 2 matchs dans un code à barres, raison pour laquelle j'avais Utilisé {2,} au lieu de {2} . Dupliquer le schéma autant de fois que possible les correspondances semblent excessives et difficiles à maintenir. Pour cette raison, je pourrais favoriser une autre solution.


C'est ce que j'ai écrit près de la fin de ma réponse. Si vous avez besoin d'un nombre dynamique de matchs, vous devez faire boucle. La boucle à travers les correspondances est-elle une solution acceptable pour vous? Si tel est le cas, je peux fournir cela, c'était juste que j'ai eu l'impression lorsque vous avez parlé des paramètres de configuration de RegEx, votre configuration ne permet pas de travailler avec quoi que ce soit d'autre qu'une seule regex -Replace qui fait tout cela.


Quoi qu'il en soit, j'ai ajouté une solution basée sur la boucle à ma réponse.


Impressionnant! Merci! Mais alors comment dites-vous quel groupe de match le résultat vient?


Les groupes sont dans le tableau GRP , à partir de l'index 1, car à l'index 0, vous trouvez la correspondance complète. Un seul des groupes de capture peut être une chaîne non vide à la fois, vous pouvez simplement ignorer la chaîne à l'index 0 et rejoindre les autres avec grp.slice (1) .join ('') . Si vous souhaitez tester un groupe individuel, do si (GRP (i)! == '') ... .