Comment ignorer les espaces dans une chaîne d'objet d'expression régulière?

107

Existe-t-il un moyen simple d'ignorer l'espace blanc dans une chaîne cible lors de la recherche de correspondances à l'aide d'un modèle d'expression régulière? Par exemple, si ma recherche porte sur "chats", je voudrais que "c ats" ou "ca ts" corresponde. Je ne peux pas supprimer les espaces au préalable car je dois trouver l'index de début et de fin de la correspondance (y compris les espaces) afin de mettre en évidence cette correspondance et tout espace doit être là à des fins de formatage.

Steven
la source

Réponses:

124

Vous pouvez coller des espaces blancs facultatifs \s*entre tous les autres caractères de votre expression régulière. Bien qu'accordé, cela deviendra un peu long.

/cats/ -> /c\s*a\s*t\s*s/

Sam Dufel
la source
Merci, on dirait que c'est la voie à suivre. Mais je viens de réaliser que je ne veux les caractères d'espacement facultatifs que s'ils suivent une nouvelle ligne. Ainsi, par exemple, "c \ n ats" ou "ca \ n ts" doit correspondre. Mais je ne voudrais pas que "c ats" corresponde s'il n'y a pas de nouvelle ligne. Des idées sur la façon dont cela pourrait être fait?
Steven le
@Steven, voyez comment je l'ai fait ci-dessous, vous pouvez facilement adapter ma solution à de tels cas spécifiques.
Bob
@chris je pense, cette expression régulière est si stricte pour uniquement les chats, elle peut aussi être écrite pour toute recherche de lettres comme celle-ci: ^([a-z]\s*)+$
Sandeep Kaur
9

Répondre au commentaire de Steven à la réponse de Sam Dufel

Merci, on dirait que c'est la voie à suivre. Mais je viens de réaliser que je ne veux les caractères d'espacement facultatifs que s'ils suivent une nouvelle ligne. Ainsi, par exemple, "c \ n ats" ou "ca \ n ts" doit correspondre. Mais je ne voudrais pas que "c ats" corresponde s'il n'y a pas de nouvelle ligne. Des idées sur la façon dont cela pourrait être fait?

Cela devrait faire l'affaire:

/c(?:\n\s*)?a(?:\n\s*)?t(?:\n\s*)?s/

Voir cette page pour toutes les différentes variantes de «chats» que cela correspond.

Vous pouvez également résoudre ce problème en utilisant des conditions , mais elles ne sont pas prises en charge dans la version javascript de regex.

Aurimas
la source
3
Tellement moche. Il doit y avoir un meilleur moyen.
james.garriss
Vous pouvez le rendre plus lisible dans la syntaxe JS (bien que la technique fonctionne dans d'autres langues) avec:new RegExp('cats'.split('').join('(?:\n\s*)?'))
brianary
7

Bien que la réponse acceptée soit techniquement correcte, une approche plus pratique, si possible, consiste simplement à supprimer les espaces à la fois de l'expression régulière et de la chaîne de recherche.

Si vous souhaitez rechercher "mes chats", au lieu de:

myString.match(/m\s*y\s*c\s*a\*st\s*s\s*/g)

Faites simplement:

myString.replace(/\s*/g,"").match(/mycats/g)

Avertissement: Vous ne pouvez pas automatiser cela sur l'expression régulière en remplaçant simplement tous les espaces par des chaînes vides, car ils peuvent se produire dans une négation ou rendre votre expression régulière invalide.

Konrad Höffner
la source
5

Vous pouvez mettre \s*entre chaque caractère dans votre chaîne de recherche, donc si vous cherchez un chat, vous utiliseriezc\s*a\s*t\s*s\s*s

C'est long mais vous pouvez bien sûr construire la chaîne dynamiquement.

Vous pouvez le voir fonctionner ici: http://www.rubular.com/r/zzWwvppSpE

Kludge
la source
3

Si vous souhaitez uniquement autoriser les espaces, alors

\bc *a *t *s\b

devrait le faire. Pour autoriser également les onglets, utilisez

\bc[ \t]*a[ \t]*t[ \t]*s\b

Supprimez les \bancres si vous souhaitez également rechercher des catsmots tels que bobcatsou catsup.

Tim Pietzcker
la source
1

Cette approche peut être utilisée pour automatiser cela (l'exemple de solution suivant est en python, bien qu'il puisse évidemment être porté dans n'importe quel langage):

vous pouvez supprimer les espaces au préalable ET enregistrer les positions des caractères autres que des espaces afin de pouvoir les utiliser plus tard pour connaître les positions des limites de chaîne correspondantes dans la chaîne d'origine comme suit:

def regex_search_ignore_space(regex, string):
    no_spaces = ''
    char_positions = []

    for pos, char in enumerate(string):
        if re.match(r'\S', char):  # upper \S matches non-whitespace chars
            no_spaces += char
            char_positions.append(pos)

    match = re.search(regex, no_spaces)
    if not match:
        return match

    # match.start() and match.end() are indices of start and end
    # of the found string in the spaceless string
    # (as we have searched in it).
    start = char_positions[match.start()]  # in the original string
    end = char_positions[match.end()]  # in the original string
    matched_string = string[start:end]  # see

    # the match WITH spaces is returned.
    return matched_string

with_spaces = 'a li on and a cat'
print(regex_search_ignore_space('lion', with_spaces))
# prints 'li on'

Si vous voulez aller plus loin, vous pouvez construire l'objet de correspondance et le renvoyer à la place, de sorte que l'utilisation de cet assistant sera plus pratique.

Et les performances de cette fonction peuvent bien sûr également être optimisées, cet exemple est juste pour montrer le chemin vers une solution.

Bob
la source