Correspond aux espaces, mais pas aux nouvelles lignes

277

Je veux parfois faire correspondre les espaces, mais pas la nouvelle ligne.

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

JoelFan
la source
4
BTW, ces personnages sont aussi « espaces blancs »: [\r\f].
Eugene Yarmash
2
@eugeney est-ce que quelqu'un fait encore des flux de formulaires? (\ f's)
Aran Mulholland
1
@AranMulholland: toute personne disposant d'une imprimante orientée caractères. La plupart des imprimantes ont un mode caractère ainsi que PostScript ou quel que soit le nom de l'interface Hewlett Packard, et pour lancer une page, vous envoyez un flux de formulaire.
Borodin
1
@Borodin Hewlett Packard s'appelle PCL (Printer Control Language).
CB_Ron

Réponses:

182

Perl versions 5.10 et plus tard filiale de soutien des classes de caractères vertical et horizontal, \vet \h, ainsi que la classe de caractère générique des espaces\s

La solution la plus propre consiste à utiliser la classe de caractères des espaces blancs horizontaux\h . Cela correspondra à l'onglet et à l'espace de l'ensemble 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

Le motif d' espace vertical\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 espaces blancs verticaux qui correspondent \vet dix-huit caractères horizontaux qui correspondent \h. \scorrespond à vingt-trois caractères

Tous les caractères d'espacement sont verticaux ou horizontaux sans chevauchement, mais ils ne sont pas des sous-ensembles appropriés car ils \hcorrespondent également à U + 00A0 NO-BREAK SPACE et \vcorrespondent également à U + 0085 NEXT LINE, aucun des deux ne correspondant à\s

Borodin
la source
7
\hne fonctionne que sur les langues prises en charge PCRE.
Avinash Raj
14
@AvinashRaj: Cette question concerne Perl, qui prend certainement en charge PCRE
Borodin
2
@AvinashRaj: Sauf que [[:blank:]]cela ne correspond pas à l'espace insécable -  ou"\xA0"
Borodin
6
\hJe veux mentionner que cela a parfaitement fonctionné pour mon cas d'utilisation qui faisait une recherche / remplacement dans Notepad ++ sur 1 ou plusieurs espaces non-new-line contigus. Rien d'autre (simple) n'a fonctionné.
squidbe
8
Ce qui rend Perl \hlégèrement non standard, c'est son inclusion de MONGOLIAN VOWEL SEPARATOR. Unicode ne le considère pas comme un espace. Pour cette raison, Perl \hdiffère de POSIX blank( [[:blank:]]en Perl, \p{Blank}en Java) et Java 8 \h. Certes, c'est un cas de bord.
Aleksandr Dubinsky
362

Utilisez un double négatif:

/[^\S\r\n]/

C'est-à-dire, pas-pas-blanc (le S majuscule complète) ou pas-retour-chariot ou pas-newline. Distribuer le non externe ( c'est-à - dire le complément ^dans la classe de caractères) avec la loi de De Morgan , cela équivaut à "des espaces mais pas un retour chariot ou une nouvelle ligne". L'inclusion des deux \ret \ndans le modèle gère correctement toutes les conventions de nouvelle ligne Unix (LF), Mac OS (CR) et DOS-ish (CR LF) .

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";
}

Production:

"" => correspond
"\ f" => correspond
"\ t" => correspond
"\ r" => aucune correspondance
"\ n" => aucune correspondance

Notez l'exclusion de l'onglet vertical, mais cela est traité dans la v5.18 .

Avant de trop objecter, la documentation Perl utilise la même technique. Une note de bas de page dans la section «Espace blanc» de perlrecharclass indique

Avant Perl v5.18, \sne correspondait pas à l'onglet vertical. [^\S\cK](obscurément) correspond à ce qui \sse faisait traditionnellement.

La même section de perlrecharclass suggère également d'autres approches qui n'offenseront pas l'opposition des professeurs de langue aux doubles négatifs.

En dehors des règles locales et Unicode ou lorsque le /acommutateur est en vigueur, " \scorrespond [\t\n\f\r ]et, à partir de Perl v5.18, l'onglet vertical, \cK". Jeter \ret \nlaisser /[\t\f\cK ]/pour les espaces correspondants, mais pas pour les retours à la ligne.

Si votre texte est Unicode, utilisez un code similaire au sous-code ci-dessous pour construire un modèle à 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 à double négatif est également pratique pour faire correspondre les caractères alphabétiques. N'oubliez pas que cela \wcorrespond à des «caractères de mots», des caractères alphabétiques et des chiffres et un soulignement. Nous, les moches américains, voulons parfois l'écrire comme, disons,

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

mais une classe de caractères à double négatif peut respecter les paramètres régionaux:

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

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

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

ou avec une propriété Unicode comme suggéré par szbalint

if (/\p{Letter}+/) { ... }
Greg Bacon
la source
4
Intelligent, mais le comportement est très surprenant, et je ne vois pas comment c'est moins gênant.
Qwertie
7
@Qwertie: qu'est-ce qui est surprenant? Moins maladroit que quoi?
2010
9
Très horrible.
9
C'est très bien. Comme demandé, vous faites correspondre les espaces (et pas seulement certains caractères d'espaces) et vous excluez le caractère de saut de ligne. Votre solution ne se préoccupe pas de la question: "quels caractères d'espaces existent", comme il ne devrait pas. C'est précisément ce que je cherchais. (Comme l'a noté @Rory, une « nouvelle ligne » peut également inclure \r, par exemple , sous Windows, alors pensez à ceux du compte non tenu de match ainsi: /[^\S\r\n]/)
Timo
1
Cela répondra certainement aux besoins du PO et de pratiquement tous ceux qui recherchent cette question (anglophones, de toute façon). Mais c'est toujours une mauvaise réponse. Il n'y a tout simplement aucune excuse pour utiliser cette solution lorsqu'elle \hest disponible.
Alan Moore
50

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

/[^\S\r\n]/

Ce regex est plus sûr que /[^\S\n]/non \r. Mon raisonnement est que Windows utilise \r\npour les retours à la ligne et Mac OS 9 utilisé \r. Il est peu probable que vous trouviez \rsans de \nnos jours, mais si vous le trouvez, cela ne pourrait pas signifier autre chose qu'une nouvelle ligne. Ainsi, puisque \rpeut signifier une nouvelle ligne, nous devons également l'exclure.

Rory O'Kane
la source
1
+1 La solution de Greg a fini par corrompre mon texte, la vôtre a bien fonctionné.
Timo Huovinen
Vous pourriez être surpris du nombre de programmes qui utilisent encore "\ r" pour les fins de ligne. Il m'a parfois fallu un certain temps pour comprendre que mon problème était que le fichier les utilisait. Ou qu'il a utilisé l'encodage de caractères MacRoman ...
mivk
2
on dirait que @Greg a d'abord eu "mal" changé et ne vous a pas crédité. C'est pourquoi je vote ici.
Andre Elrico
14

Le regex ci-dessous correspondrait aux espaces blancs mais pas à un nouveau caractère de ligne.

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

DEMO

Si vous souhaitez également ajouter le retour chariot, ajoutez-le \ravec l' |opérateur à l'intérieur de l'anticipation négative.

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

DEMO

Ajoutez +après le groupe non capturé pour faire correspondre un ou plusieurs espaces blancs.

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

DEMO

Je ne sais pas pourquoi vous avez omis de mentionner la classe de caractères POSIX [[:blank:]]qui correspond aux espaces blancs horizontaux ( espaces et tabulations ). Cette classe chrérique POSIX fonctionnerait sur BRE ( Expressions régulières de base ), ERE ( Expression régulière étendue ), PCRE ( Expression régulière compatible Perl ).

DEMO

Avinash Raj
la source
C'est la meilleure solution!
loretoparisi
13

Ce que vous recherchez, c'est la blankclasse de caractères POSIX . En Perl, il est référencé comme:

[[:blank:]]

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

\p{Blank}

Comparé au similaire \h, POSIX blankest supporté par quelques moteurs regex supplémentaires ( référence ). Un avantage majeur est que sa définition est fixée dans l' Annexe C: Propriétés de compatibilité des expressions régulières Unicode et standard dans toutes les versions regex qui prennent en charge Unicode. (En Perl, par exemple, \hchoisit d'inclure en plus le MONGOLIAN VOWEL SEPARATOR.) Cependant, un argument en faveur de cela \hest qu'il détecte toujours les caractères Unicode (même si les moteurs ne sont pas d'accord sur lequel), tandis que les classes de caractères POSIX sont souvent par défaut ASCII -seulement (comme en Java).

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

Le séparateur de voyelles mongole susmentionné n'est pas inclus pour ce qui est probablement une bonne raison. Il, avec 200C et 200D, se produit dans les mots (AFAIK), et brise donc la règle cardinale que tous les autres espaces obéissent: vous pouvez en faire un tokenize. Ils ressemblent plus à des modificateurs. Cependant, ZERO WIDTH SPACE, WORD JOINERet ZERO WIDTH NON-BREAKING SPACE(si elle utilisé comme autre qu'une marque d'ordre d'octet) s'adapter à la règle des espaces dans mon livre. Par conséquent, je les inclue dans ma classe de caractères d'espaces blancs horizontaux.

En Java:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
Aleksandr Dubinsky
la source
Vous devez ajouter les indicateurs de compilation regexp appropriés à la compilation Java et exécuter Java 7 ou une version ultérieure. En tout état de cause, la question ne concernait pas du tout Java ou PCRE, donc tout cela n'a pas d'importance.
tchrist
@tchrist Merci de l'avoir signalé. Je mettrai à jour ma réponse. Je ne suis pas d'accord, cependant, que ma réponse ne soit pas pertinente. Ce qui est sans importance, c'est la perlbalise de la question d'origine.
Aleksandr Dubinsky
1
@AleksandrDubinsky, \ p {Blank} n'est pas pris en charge en JavaScript, donc certainement pas "standard pour toutes les saveurs regex" -1
Valentin Vasilyev
Le plus instructif. Je trouve troublant de savoir qu'il n'existe pas de classe de caractère sténographique "espace blanc" général et complet, et que des horreurs comme celles-ci [\p{Blank}\u200b\u180e]sont nécessaires. Certes, il est logique qu'un séparateur de voyelles ne soit pas considéré comme un espace blanc, mais pourquoi l'espace de largeur nulle n'est pas dans des classes comme \set \p{Blank}, me bat.
Timo
Suivi: J'ai lu que les deux sont considérés comme «neutres sur le plan des limites», bien que cela n'explique pas pourquoi .
Timo
-4

m/ /gdonnez juste de l'espace / /, et cela fonctionnera. Ou utilisez \S- il remplacera tous les caractères spéciaux tels que tabulation, sauts de ligne, espaces, etc.

saiprathapreddy.obula
la source