189 votes

Comment diviser une longue expression régulière en plusieurs lignes en JavaScript ?

J'ai une expression régulière très longue, que je souhaite diviser en plusieurs lignes dans mon code JavaScript afin de conserver une longueur de 80 caractères pour chaque ligne, conformément aux règles de JSLint. C'est tout simplement mieux pour la lecture, je pense. Voici un exemple d'expression régulière :

var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

160voto

korun Points 1265

Dans le prolongement de la réponse de @KooiInc, vous pouvez éviter d'échapper manuellement à chaque caractère spécial en utilisant la fonction source de l RegExp objet.

Exemple :

var urlRegex= new RegExp(''
  + /(?:(?:(https?|ftp):)?\/\/)/.source     // protocol
  + /(?:([^:\n\r]+):([^@\n\r]+)@)?/.source  // user:pass
  + /(?:(?:www\.)?([^\/\n\r]+))/.source     // domain
  + /(\/[^?\n\r]+)?/.source                 // request
  + /(\?[^#\n\r]*)?/.source                 // query
  + /(#?[^\n\r]*)?/.source                  // anchor
);

ou si vous voulez éviter de répéter le .source vous pouvez le faire en utilisant la propriété Array.map() fonction :

var urlRegex= new RegExp([
  /(?:(?:(https?|ftp):)?\/\/)/      // protocol
  ,/(?:([^:\n\r]+):([^@\n\r]+)@)?/  // user:pass
  ,/(?:(?:www\.)?([^\/\n\r]+))/     // domain
  ,/(\/[^?\n\r]+)?/                 // request
  ,/(\?[^#\n\r]*)?/                 // query
  ,/(#?[^\n\r]*)?/                  // anchor
].map(function(r) {return r.source}).join(''));

En ES6, la fonction map peut être réduite à : .map(r => r.source)

141voto

KooiInc Points 38845

Vous pourriez le convertir en une chaîne de caractères et créer l'expression en appelant new RegExp() :

var myRE = new RegExp (['^(([^<>()[\]\\.,;:\\s@\"]+(\\.[^<>(),[\]\\.,;:\\s@\"]+)*)',
                        '|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                        '[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\\.)+',
                        '[a-zA-Z]{2,}))$'].join(''));

Notes :

  1. lors de la conversion de la expression littérale en une chaîne de caractères, vous devez échapper toutes les barres obliques inverses car celles-ci sont consommées lors de l'évaluation d'un fichier littéral de chaîne de caractères . (Voir le commentaire de Kayo pour plus de détails).
  2. RegExp accepte les modificateurs comme second paramètre

    /regex/g => new RegExp('regex', 'g')

[ Addition ES20xx (modèle étiqueté)]

Dans ES20xx, vous pouvez utiliser Modèles étiquetés . Voir l'extrait.

Nota:

  • L'inconvénient ici est que vous ne pouvez pas utiliser d'espace dans la chaîne d'expression régulière (utilisez toujours \s , \s+ , \s{1,x} , \t , \n etc).

    (() => { const createRegExp = (str, opts) => new RegExp(str.raw[0].replace(/\s/gm, ""), opts || ""); const yourRE = createRegExp ^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)| (\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])| (([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$; console.log(yourRE); const anotherLongRE = createRegExp (\byyyy\b)|(\bm\b)|(\bd\b)|(\bh\b)|(\bmi\b)|(\bs\b)|(\bms\b)| (\bwd\b)|(\bmm\b)|(\bdd\b)|(\bhh\b)|(\bMI\b)|(\bS\b)|(\bMS\b)| (\bM\b)|(\bMM\b)|(\bdow\b)|(\bDOW\b) ${"gi"}; console.log(anotherLongRE); })();

33voto

Riccardo Galli Points 2653

Utilisation de chaînes de caractères dans new RegExp est maladroite car vous devez échapper tous les antislashes. Vous pouvez écrire des regex plus petites et les concaténer.

Divisons cette regex

/^foo(.*)\bar$/

Nous utiliserons plus tard une fonction pour rendre les choses plus belles.

function multilineRegExp(regs, options) {
    return new RegExp(regs.map(
        function(reg){ return reg.source; }
    ).join(''), options);
}

Et maintenant, faisons du rock

var r = multilineRegExp([
     /^foo/,  // we can add comments too
     /(.*)/,
     /\bar$/
]);

Comme cela a un coût, essayez de construire la véritable regex une seule fois et utilisez-la ensuite.

18voto

Hashbrown Points 1888

Grâce au monde merveilleux de littéraux de modèle vous pouvez désormais écrire de gros articles, sur plusieurs lignes et bien commentés, et même sémantiquement imbriqués regex dans ES6.

//build regexes without worrying about
// - double-backslashing
// - adding whitespace for readability
// - adding in comments
let clean = (piece) => (piece
    .replace(/((^|\n)(?:[^\/\\]|\/[^*\/]|\\.)*?)\s*\/\*(?:[^*]|\*[^\/])*(\*\/|)/g, '$1')
    .replace(/((^|\n)(?:[^\/\\]|\/[^\/]|\\.)*?)\s*\/\/[^\n]*/g, '$1')
    .replace(/\n\s*/g, '')
);
window.regex = ({raw}, ...interpolations) => (
    new RegExp(interpolations.reduce(
        (regex, insert, index) => (regex + insert + clean(raw[index + 1])),
        clean(raw[0])
    ))
);

En utilisant ceci, vous pouvez maintenant écrire des regex comme ceci :

let re = regex`I'm a special regex{3} //with a comment!`;

Sorties

/I'm a special regex{3}/

Ou qu'en est-il de la multiligne ?

'123hello'
    .match(regex`
        //so this is a regex

        //here I am matching some numbers
        (\d+)

        //Oh! See how I didn't need to double backslash that \d?
        ([a-z]{1,3}) /*note to self, this is group #2*/
    `)
    [2]

Sorties hel soigné !
"Et si j'avais besoin de rechercher une nouvelle ligne ? \n idiot !
Cela fonctionne sur mon Firefox et mon Chrome.


Ok, "que diriez-vous de quelque chose d'un peu plus complexe ?"
Bien sûr, voici un morceau d'un analyseur JS de déstructuration d'objet sur lequel je travaillais :

regex`^\s*
    (
        //closing the object
        (\})|

        //starting from open or comma you can...
        (?:[,{]\s*)(?:
            //have a rest operator
            (\.\.\.)
            |
            //have a property key
            (
                //a non-negative integer
                \b\d+\b
                |
                //any unencapsulated string of the following
                \b[A-Za-z$_][\w$]*\b
                |
                //a quoted string
                //this is #5!
                ("|')(?:
                    //that contains any non-escape, non-quote character
                    (?!\5|\\).
                    |
                    //or any escape sequence
                    (?:\\.)
                //finished by the quote
                )*\5
            )
            //after a property key, we can go inside
            \s*(:|)
      |
      \s*(?={)
        )
    )
    ((?:
        //after closing we expect either
        // - the parent's comma/close,
        // - or the end of the string
        \s*(?:[,}\]=]|$)
        |
        //after the rest operator we expect the close
        \s*\}
        |
        //after diving into a key we expect that object to open
        \s*[{[:]
        |
        //otherwise we saw only a key, we now expect a comma or close
        \s*[,}{]
    ).*)
$`

Il produit /^\s*((\})|(?:[,{]\s*)(?:(\.\.\.)|(\b\d+\b|\b[A-Za-z$_][\w$]*\b|("|')(?:(?!\5|\\).|(?:\\.))*\5)\s*(:|)|\s*(?={)))((?:\s*(?:[,}\]=]|$)|\s*\}|\s*[{[:]|\s*[,}{]).*)$/

Et le faire fonctionner avec une petite démo ?

let input = '{why, hello, there, "you   huge \\"", 17, {big,smelly}}';
for (
    let parsed;
    parsed = input.match(r);
    input = parsed[parsed.length - 1]
) console.log(parsed[1]);

Sorties réussies

{why
, hello
, there
, "you   huge \""
, 17
,
{big
,smelly
}
}

Notez la capture réussie de la chaîne de caractères citée.
Je l'ai testé sur Chrome et Firefox, il fonctionne à merveille !

Si <a href="https://stackoverflow.com/a/60026664/2518317">curieux vous pouvez vérifier ce que je faisais </a>y <a href="https://jsfiddle.net/anmb03jf/" rel="noreferrer">sa démonstration </a>.<br>Bien que cela ne fonctionne que sur Chrome, car Firefox ne prend pas en charge les références arrière ou les groupes nommés. Notez donc que l'exemple donné dans cette réponse est en fait une version édulcorée et qu'il peut facilement se faire piéger en acceptant des chaînes de caractères invalides.

11voto

Jamesfo Points 326

Il y a de bonnes réponses ici, mais pour être complet, quelqu'un devrait mentionner la caractéristique principale de Javascript, à savoir l'héritage avec la fonction chaîne des prototypes . Quelque chose comme ceci illustre l'idée :

RegExp.prototype.append = function(re) {
  return new RegExp(this.source + re.source, this.flags);
};

let regex = /[a-z]/g
.append(/[A-Z]/)
.append(/[0-9]/);

console.log(regex); //=> /[a-z][A-Z][0-9]/g

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X