2016-07-16 1 views
1

Hyphenated J'ai un regex perl qui convertit les traits d'union aux espaces, par exemple: -Perl Regex Retirez Hyphen mais Ignorer les mots spécifiques

$string =~ s/-/ /g; 

J'ai besoin de modifier cela pour ne pas tenir compte des phrases spécifiques et non césure remplacer le trait d'union par exemple dans une chaîne comme ceci:

"use-either-dvi-d-or-dvi-i" 

Je souhaite ne pas remplacer le trait d'union dans dvi-d et dvi-i il lit:

"use either dvi-d or dvi-i" 

J'ai essayé différents regard négatif matchs à venir, mais a lamentablement échoué .

+1

Qu'avez-vous essayé? Est-ce que 'dvi-i' et' dvi-d' sont les seules phrases que vous voulez exclure? Ou y a-t-il une "liste blanche" d'entre eux? –

+0

En fait, une liste blanche peut être meilleure car il peut y avoir d'autres termes hyphanated je dois garder –

Répondre

4

Vous pouvez utiliser cette expression régulière PCRE avec les verbes (*SKIP)(*F) sauter certains mots de votre match:

dvi-[id](*SKIP)(*F)|- 

RegEx Demo

Cela va sauter les mots dvi-i et dvi-d pour le fractionnement en raison de l'utilisation de (*SKIP)(*F).

Pour votre code:

$string =~ s/dvi-[id](*SKIP)(*F)|-/ /g; 

Perl Code Demo


Il existe une solution à base lookarounds alternatives ainsi:

/(?<!dvi)-|-(?![di])/ 

Ce qui signifie essentiellement trait d'union match si elle est non précédé de dvi OU s'il n'est pas suivi par d ou i, en s'assurant ainsi de ne pas correspondre - lorsque nous avons dvi sur LHS et [di] sur RHS.

code Perl:

$string =~ s/(?<!dvi)-|-(?![di])/ /g; 

Perl Code Demo 2

+1

votre sortie de démonstration regEX (** utiliser soit '-' dvi-d ou-dvi-i **) n'est pas aussi attendu que la sortie désirée . – Arijit

+0

Bon point @Arijit, c'est corrigé maintenant, – anubhava

+0

Je ne pense pas pouvoir utiliser (* SKIP) en perl, ça ne l'aime pas? –

1
$string =~ s/(?<!dvi)-(?![id])|(?<=dvi)-(?![id])|(?<!dvi)-(?=[id])/ /g; 

Tout en utilisant simplement (?<!dvi)-(?![id]) vous exclure également dvi-x ou x-i, où x peut être tout caractère.

+1

Qu'est ce que c'est? Pourquoi utilisez-vous l'alternance? – rock321987

+0

J'ai ajouté une explication. – horcrux

+0

Je pense OP est heureux d'exclure '-' entre' dvi' et 'x' .. – rock321987

-2

nous pouvons ignorer les mots spécifiques à l'aide Look-avant et Look-derrière négatif négatif

Exemple:

(?!pattern) 
is a negative look-ahead assertion 

dans votre cas, le motif est

$string =~ s/(?<!dvi)-(?<![id])/ /g; 

sortie :

use either dvi-d or dvi-i 

Référence: http://www.perlmonks.org/?node_id=518444

Espérons que cela vous aidera.

+0

Il ne se sépare pas sur 'dvi-abc' – anubhava

+0

L'addition de' \ + 'résoudra votre problème. Modèle précédent pour l'exemple d'utilisateur uniquement. – Arijit

+0

Echappé '\ +' après que '\ w' correspond à un' + 'litéral – anubhava

0

Il est peu probable que vous puissiez obtenir une solution regex simple et directe à cela. Cependant, vous pouvez essayer ce qui suit:

#!/usr/bin/env perl 

use strict; 
use warnings; 

my %whitelist = map { $_ => 1 } qw(dvi-d dvi-i); 

my $string = 'use-either-dvi-d-or-dvi-i'; 

while ($string =~ m{ ([^-]+) (-) ([^-]+) }gx) { 
    my $segment = substr($string, $-[0], $+[0] - $-[0]); 
    unless ($whitelist{ $segment }) { 
     substr($string, $-[2], 1, ' '); 
    } 
    pos($string) = $-[ 3 ]; 
} 

print $string, "\n"; 

Le tableau @- contient les décalages de départ des groupes appariés, et le tableau @+ contient les décalages extrémités. Dans les deux cas, l'élément 0 fait référence à la correspondance complète.

je devais recourir à quelque chose comme ça because of how \G works:

Notez également que s/// refusera de remplacer une partie d'une substitution qui a déjà été remplacé; Ainsi, par exemple cela arrête après la première itération, plutôt que itérer son chemin en arrière à travers la chaîne:

$_ = "123456789"; 
    pos = 6; 
    s/.(?=.\G)/X/g; 
    print;  # prints 1234X6789, not XXXXX6789 

Peut-être @tchrist peut comprendre comment plier diverses affirmations à sa volonté.