349 votes

Correspond aux espaces mais pas aux nouvelles lignes

Je veux parfois faire correspondre les espaces mais pas les nouvelles lignes.

Jusqu'à présent, j'ai eu recours à [ \t] . Y a-t-il un moyen moins gênant ?

5 votes

D'ailleurs, ces caractères sont aussi des "espaces blancs" : [\r\f] .

2 votes

@eugeney, est-ce que quelqu'un fait encore de l'alimentation par formulaire ? ( \f 's)

1 votes

@AranMulholland : Tous ceux qui ont une imprimante orientée caractères. La plupart des imprimantes disposent d'un mode caractère ainsi que de PostScript ou d'un autre nom pour l'interface Hewlett Packard, et pour lancer une page, il faut envoyer un flux de formulaires.

453voto

Greg Bacon Points 50449

Utilisez un double négatif :

/[^\S\r\n]/

C'est-à-dire, pas-pas-d'espace blanc (le S majuscule complète) ou pas-de-retour-de-chariot ou pas-de-nouvelle-ligne. La distribution du not extérieur ( c'est-à-dire le complément ^ dans la classe de caractères) avec La loi de Morgan cela équivaut à "espace blanc mais pas de retour chariot ni de nouvelle ligne". En incluant à la fois \r y \n dans le motif gère correctement tous les systèmes Unix (LF), Mac OS classique (CR) et DOS (CR LF). conventions relatives aux nouvelles lignes .

Pas besoin de me croire sur parole :

#! /usr/bin/env perl

use strict;
use warnings;

use 5.005;  # for qr//

my $ws_not_crlf = qr/[^\S\r\n]/;

for (' ', '\f', '\t', '\r', '\n') {
  my $qq = qq["$_"];
  printf "%-4s => %s\n", $qq,
    (eval $qq) =~ $ws_not_crlf ? "match" : "no match";
}

Sortie :

" "  => match
"\\f" => match
"\\t" => match
"\\r" => no match
"\\n" => no match

Notez l'exclusion de la tabulation verticale, mais ceci est abordé dans la v5.18 .

Avant d'objecter trop sévèrement, sachez que la documentation de Perl utilise la même technique. Une note de bas de page dans le document Section "Whitespace" de perlrecharclass lit

Avant la version 5.18 de Perl, \s ne correspondait pas à l'onglet vertical. [^\S\cK] correspond (obscurément) à ce que \s traditionnellement.

En même section de perlrecharclass suggère également d'autres approches qui ne heurteront pas l'opposition des professeurs de langues aux doubles négations.

En dehors des règles locales et de l'Unicode ou lorsque l'élément /a est en vigueur, " \s correspond à [\t\n\f\r ] et, à partir de Perl v5.18, l'onglet vertical, \cK ." Jeter \r y \n de laisser /[\t\f\cK ]/ pour la correspondance des espaces mais pas des nouvelles lignes.

Si votre texte est en Unicode, utilisez un code similaire au sous ci-dessous pour construire un motif à partir du tableau dans la section de documentation susmentionnée .

sub ws_not_nl {
  local($_) = <<'EOTable';
0x0009        CHARACTER TABULATION   h s
0x000a              LINE FEED (LF)    vs
0x000b             LINE TABULATION    vs  [1]
0x000c              FORM FEED (FF)    vs
0x000d        CARRIAGE RETURN (CR)    vs
0x0020                       SPACE   h s
0x0085             NEXT LINE (NEL)    vs  [2]
0x00a0              NO-BREAK SPACE   h s  [2]
0x1680            OGHAM SPACE MARK   h s
0x2000                     EN QUAD   h s
0x2001                     EM QUAD   h s
0x2002                    EN SPACE   h s
0x2003                    EM SPACE   h s
0x2004          THREE-PER-EM SPACE   h s
0x2005           FOUR-PER-EM SPACE   h s
0x2006            SIX-PER-EM SPACE   h s
0x2007                FIGURE SPACE   h s
0x2008           PUNCTUATION SPACE   h s
0x2009                  THIN SPACE   h s
0x200a                  HAIR SPACE   h s
0x2028              LINE SEPARATOR    vs
0x2029         PARAGRAPH SEPARATOR    vs
0x202f       NARROW NO-BREAK SPACE   h s
0x205f   MEDIUM MATHEMATICAL SPACE   h s
0x3000           IDEOGRAPHIC SPACE   h s
EOTable

  my $class;
  while (/^0x([0-9a-f]{4})\s+([A-Z\s]+)/mg) {
    my($hex,$name) = ($1,$2);
    next if $name =~ /\b(?:CR|NL|NEL|SEPARATOR)\b/;
    $class .= "\\N{U+$hex}";
  }

  qr/[$class]/u;
}

Autres applications

L'astuce du double négatif est également pratique pour faire correspondre des caractères alphabétiques. Rappelez-vous que \w correspond à des "caractères de mot", des caractères alphabétiques et les chiffres et les traits de soulignement. Nous, les vilains Américains, voulons parfois l'écrire comme, par exemple ,

if (/[A-Za-z]+/) { ... }

mais une classe de caractères double-négative peut respecter la locale :

if (/[^\W\d_]+/) { ... }

Exprimer "un caractère de mot mais pas un chiffre ou un trait de soulignement" de cette manière est un peu opaque. Une classe de caractères POSIX communique l'intention plus directement

if (/[[:alpha:]]+/) { ... }

ou avec une propriété Unicode comme szbalint Proposition de

if (/\p{Letter}+/) { ... }

4 votes

Astucieux, mais le comportement est très surprenant, et je ne vois pas en quoi il est moins gênant.

8 votes

@Qwertie : qu'est-ce qui est surprenant ? Moins gênant que quoi ?

0 votes

Comment puis-je imbriquer cette expression dans une autre ? Par exemple, remplacer " \s " avec elle dans /(\+|0|\()[\d()\s-]{6,20}\d/g ? Thx

224voto

Borodin Points 52478

Les versions 5.10 et ultérieures de Perl prennent en charge les classes de caractères verticaux et horizontaux subsidiaires, \v y \h ainsi que la classe de caractères d'espacement générique \s

La solution la plus propre est d'utiliser le espace blanc horizontal classe de caractères \h . Cela correspondra à la tabulation et à l'espace du jeu ASCII, à l'espace insécable de l'ASCII étendu ou à l'un de ces caractères Unicode.

U+0009 CHARACTER TABULATION
U+0020 SPACE
U+00A0 NO-BREAK SPACE (not matched by \s)

U+1680 OGHAM SPACE MARK
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN SPACE
U+2003 EM SPACE
U+2004 THREE-PER-EM SPACE
U+2005 FOUR-PER-EM SPACE
U+2006 SIX-PER-EM SPACE
U+2007 FIGURE SPACE
U+2008 PUNCTUATION SPACE
U+2009 THIN SPACE
U+200A HAIR SPACE
U+202F NARROW NO-BREAK SPACE
U+205F MEDIUM MATHEMATICAL SPACE
U+3000 IDEOGRAPHIC SPACE

En espace vertical motif \v est moins utile, mais correspond à ces caractères

U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0085 NEXT LINE (not matched by \s)

U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR

Il y a sept caractères d'espacement vertical qui correspondent à \v et dix-huit horizontaux qui correspondent \h . \s correspond à vingt-trois caractères

Tous les caractères d'espacement sont soit vertical o horizontal sans chevauchement, mais ce ne sont pas des sous-ensembles corrects car \h correspond aussi à U+00A0 NO-BREAK SPACE, et \v correspond également à U+0085 NEXT LINE, qui ne sont pas pris en compte par l'option \s

10 votes

\h ne fonctionne que sur les langues qui supportent PCRE .

17 votes

@AvinashRaj : Cette question concerne Perl, qui supporte certainement PCRE.

0 votes

@AleksandrDubinsky cette notation POSIX vide [[:blank:]] fonctionnera dans la plupart des langues.

59voto

Rory O'Kane Points 4866

Une variation sur La réponse de Greg qui inclut également les retours de chariot :

/[^\S\r\n]/

Cette regex est plus sûre que /[^\S\n]/ sans \r . Mon raisonnement est que Windows utilise \r\n pour les nouvelles lignes, et Mac OS 9 utilisait \r . Vous avez peu de chances de trouver \r sans \n de nos jours, mais si vous le trouvez, il ne peut signifier autre chose qu'une nouvelle ligne. Ainsi, depuis \r peut signifier une nouvelle ligne, nous devrions l'exclure également.

1 votes

+1 La solution de Greg a fini par corrompre mon texte, le tien a bien fonctionné.

0 votes

Vous pourriez être surpris de voir combien de programmes utilisent encore " \r "pour les fins de ligne. Il m'a fallu parfois un certain temps pour comprendre que mon problème était que le fichier utilisait ces éléments. Ou qu'il utilisait le codage de caractères MacRoman...

5 votes

Il semble que @Greg l'ait d'abord "mal" changé et ne vous ait pas crédité. C'est pourquoi je vote ici.

15voto

Avinash Raj Points 23485

La regex ci-dessous correspondrait aux espaces blancs mais pas au caractère de nouvelle ligne.

(?:(?!\n)\s)

DEMO

Si vous voulez ajouter le retour de chariot aussi, alors ajoutez \r avec le | à l'intérieur du lookahead négatif.

(?:(?![\n\r])\s)

DEMO

Ajouter + après le groupe non capturant pour correspondre à un ou plusieurs espaces blancs.

(?:(?![\n\r])\s)+

DEMO

Je ne sais pas pourquoi vous avez oublié de mentionner la classe de caractères POSIX. [[:blank:]] qui correspond à tous les espaces horizontaux ( espaces et tabulations ). Cette classe de chractère POSIX fonctionnerait sur BRE( Expressions rationnelles de base ), ERE( Expression régulière étendue ), PCRE( Expression régulière compatible avec Perl ).

DEMO

0 votes

C'est la meilleure solution !

14voto

Aleksandr Dubinsky Points 2488

Ce que vous cherchez, c'est le POSIX blank classe de caractères. En Perl, elle est référencée comme :

[[:blank:]]

en Java (n'oubliez pas d'activer UNICODE_CHARACTER_CLASS ):

\p{Blank}

Par rapport à des \h POSIX blank est supporté par quelques moteurs regex supplémentaires ( référence ). Un avantage majeur est que sa définition est fixée en Annexe C : Propriétés de compatibilité des expressions régulières Unicode et standard dans toutes les saveurs de regex qui supportent Unicode. (En Perl, par exemple, \h choisit d'inclure en plus le MONGOLIAN VOWEL SEPARATOR .) Cependant, un argument en faveur de \h est qu'il détecte toujours les caractères Unicode (même si les moteurs ne sont pas d'accord sur lesquels), alors que les classes de caractères POSIX sont souvent par défaut uniquement ASCII (comme dans Java).

Mais le problème est que même en s'en tenant à Unicode, le problème n'est pas résolu à 100%. Considérez les caractères suivants qui ne sont pas considérés comme des espaces blancs dans Unicode :

Le séparateur de voyelles mongolien mentionné plus haut n'est pas inclus pour ce qui est probablement une bonne raison. Il, ainsi que 200C et 200D, se trouvent à l'intérieur des mots (AFAIK), et donc enfreint la règle cardinale à laquelle tous les autres espaces blancs obéissent : vous pouvez les utiliser pour la tokénisation. Ce sont plutôt des modificateurs. Cependant, ZERO WIDTH SPACE , WORD JOINER y ZERO WIDTH NON-BREAKING SPACE (s'ils sont utilisés autrement que comme marque d'ordre d'octet) correspondent à la règle de l'espace blanc dans mon livre. Par conséquent, je les inclus dans ma classe de caractères d'espacement horizontal.

En Java :

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"

0 votes

Vous devez ajouter les drapeaux de compilation de regexp appropriés à la compilation Java, et utiliser Java 7 ou une version ultérieure. Quoi qu'il en soit, la question ne portait pas du tout sur Java ou PCRE, donc tout cela est sans importance.

0 votes

@tchrist Merci d'avoir signalé ce point. Je vais mettre à jour ma réponse. Je ne suis pas d'accord, cependant, pour dire que ma réponse n'est pas pertinente. Ce qui est immatériel, c'est le perl dans la question originale.

1 votes

@AleksandrDubinsky, \p {Blank} n'est pas pris en charge par JavaScript, et n'est donc pas "standard pour tous les types de regex" -1

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