Que signifie \? signifie dans une expression régulière?

16

La commande suivante est utilisée pour rechercher un numéro de téléphone à 7 chiffres:

grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file

Qu'est - ce que \?veut dire?

user5997
la source

Réponses:

21

C'est comme ?dans de nombreux autres moteurs d'expression régulière, et signifie "correspondre à zéro ou à l'un de ceux qui l'ont précédé".

Dans votre exemple, le \?est appliqué au [ -], ce qui signifie qu'il essaie de faire correspondre un espace ou un moins, mais que l'espace ou le moins est facultatif.

Donc, chacun d'entre eux correspondra:

555 1234
555-1234
5551234

La raison pour laquelle il est écrit \?plutôt que ?pour une compatibilité ascendante.

La version originale greputilisait un autre type d'expression régulière appelé "expression régulière de base", où ?il s'agissait simplement d'un point d'interrogation littéral.

Pour que GNU grep puisse avoir la fonctionnalité zéro ou une, ils l'ont ajoutée, mais ont dû utiliser la \?syntaxe pour que les scripts utilisés ?fonctionnent toujours comme prévu.

Notez que grep a une -Eoption qui lui fait utiliser le type d'expression régulière le plus courant, appelé "expressions régulières étendues".

man 1 grep:

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression
          (ERE, see below).  (-E is specified by POSIX.)

   -G, --basic-regexp
          Interpret PATTERN as a basic regular expression (BRE, see below).
          This is the default.

...

Repetition
    A regular expression may be followed by one of several repetition operators:
    ?      The preceding item is optional and matched at most once.

...

    grep understands three different versions of regular expression syntax:
    “basic,” “extended” and “perl.”

...

Basic vs Extended Regular Expressions
    In basic regular expressions the meta-characters ?, +, {, |, (, and )
    lose their special meaning; instead use the backslashed versions
    \?, \+, \{, \|, \(, and \).

Plus d'infos:

Mikel
la source
La egrepcommande est équivalente à grep -E. Pour les versions autres que GNU grep, greppeut ou non accepter l' -Eoption, et egreppeut être un programme distinct.
Keith Thompson
@KeithThompson, grep -Eest la voie officielle POSIX. egrepa été déconseillé dans susv2 (1997) et supprimé dans susv3 (2001) des spécifications POSIX et Unix.
Stéphane Chazelas
1
\?est un GNUisme cependant.
Stéphane Chazelas
8

Malheureusement, la syntaxe exacte des expressions régulières varie légèrement entre les différents programmes: les expressions régulières grep ne sont pas exactement les mêmes que les expressions régulières sed, qui ne sont pas exactement les mêmes que les expressions régulières Emacs, qui ne sont pas exactement les mêmes que les expressions régulières C ++, etc. sur. Pour aggraver les choses, même un outil "standard" comme grep peut varier légèrement entre différents systèmes d'exploitation de type Unix.

Dans une expression régulière, certains caractères ont une signification spéciale (comme les crochets dans votre exemple) et reviennent à leur signification normale en tant que caractères littéraux lorsque vous les "échappez" en mettant une barre oblique inverse devant eux (donc une parenthèse littérale serait écrit comme \ [). D'autres fonctionnent dans l'autre sens et ne prennent une signification spéciale que lorsqu'ils sont échappés (par exemple, n simple n'est qu'une lettre, mais \ n est un saut de ligne). Et ceux-ci, encore une fois, peuvent varier entre les implémentations d'expression régulière.

Dans la plupart des implémentations d'expression régulière, un point d'interrogation signifie que l'élément précédent est facultatif, tandis qu'un point d'interrogation échappé (\?) Est un point d'interrogation littéral. Mais dans quelques dialectes, c'est l'inverse. Votre exemple pourrait avoir un sens dans les deux sens, mais je suppose que vous avez l'un des dialectes où? est un littéral et \? est le symbole facultatif. Donc, votre expression régulière signifie probablement "trois chiffres, éventuellement suivis d'un espace ou d'un tiret, suivis de quatre chiffres".

(Un autre indice peut être vu dans des constructions comme \ {3 \}, qui est clairement destiné à signifier "exactement 3 de l'élément précédent". Dans la plupart des dialectes regex, cela serait écrit {3}, et \ {serait une accolade littérale .)

Ross Smith
la source
6

Il s'agit d'un résumé rapide des informations déjà contenues dans les autres réponses.

Dans grep, ?correspond à un caractère littéral d'interrogation et \?indique zéro ou une occurrence de tout ce qui le précède. Ainsi, dans l'exemple de votre question, [ -]\?correspond soit à un espace, soit à un tiret, soit à rien.

Dans egrepou grep -E, c'est l'inverse; \?correspond à un point d'interrogation littéral et ?indique zéro ou une occurrence.

Cela s'applique à GNU grep; les détails des implémentations grep non GNU peuvent différer légèrement. En particulier, grepet egrepétaient historiquement deux programmes distincts, et je ne pense pas que les anciens grepavaient la -Epossibilité. POSIX le précise grep -E, mais (j'ai été surpris de le découvrir) ne le mentionne pas egrep.

Keith Thompson
la source