Thread Maske Regex (14 answers)
Opened by hobbyperler at 2009-09-12 09:47

MatthiasW
 2009-09-13 16:32
#125709 #125709
User since
2008-01-27
367 Artikel
BenutzerIn
[default_avatar]
Okay, dann hier nochmal der Code, etwas verändert und kommentiert, mit einem kleinen Beispiel:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/perl

use strict;
use warnings;

# In %special werden die Bedeutungen der, von Sternchen umgebenen Ausdrücke
# abgelegt:
my %special = (
    'id' => "\\d+", # *id* => \d+
    '' => "\\*",    # **   => \*
);

sub mask2regex {
    my( $mask ) = @_;
    
    # Hier nutze ich ein feature von split(). Falls geklammerte Ausdrücke in
    # dem Regex vorhanden sind, werden die matchenden Teile an ihrer jeweiligen
    # Position mit zurückgeliefert. Die Wörter, die von Sternchen umgeben sind,
    # stehen also an ungeraden, die konstanten Teile an geraden Indizes in @rx:
    my @rx = split /\*(\w*)\*/, $mask;

    # Jetzt werden die einzelnen Teile wieder zusammengefuegt. Dabei werden
    # Zeichen mit besonderer Bedeutung in den konstanten Teilen escaped
    # (\Q...\E) und die Stern-Ausdrücke werden durch ihre Pendants aus %special
    # ersetzt:
    my $rx;
    $rx .= $_ % 2 == 0 ? "\Q$rx[$_]\E" : $special{$rx[$_]} for 0 .. $#rx;
    
    # Mir ist noch aufgefallen, dass der Ausdruck vermutlich nicht matchen
    # soll, wenn hinten oder vorne noch etwas steht (falls dem nicht so ist
    # kannst du die nächste Zeile einfach löschen):
    $rx = '\\A'. $rx .'\\z';

    # Zuletzt wird $rx als regulärer Ausdruck zurückgegeben, sodass man ihn
    # auch wie einen benutzen kann ('irgendwas' =~ $rx):
    return qr/$rx/;
} # mask2regex

# irgendwo holst du dir die Maske her:
my $mask = '*id*-datei.dat';

# dann erstellst du den regulären Ausdruck:
my $regex = mask2regex($mask); # qr/(?-xism:\A\d+\-datei\.dat\z)/

# und testest die Dateinamen auf ihn:
my @files = qw( -datei.dat 02-datei.dat 45-datei-dat 1-datei.dat.csv
                abc32-datei.dat );

print "$_\n" for grep $_ =~ $regex, @files;
Du kannst die Rückgabe von mask2regex() also wie einen herkömmlichen regulären Ausdruck verwenden. Falls es noch andere Stern-Ausdrücke gibt, kannst du diese in %special vermerken.

edit: Allerdings ist mir gerade aufgefallen, das pq's Lösung eleganter ist:
Code (perl): (dl )
1
2
3
my $regex = quotemeta $mask;
$regex =~ s/\\\*(\w*)\\\*/$special{$1}/g;
$regex = '\\A'. $regex .'\\z';

MfG
Last edited: 2009-09-13 16:39:50 +0200 (CEST)
perl -E'*==*",s;;%ENV=~m,..$,,$&+42;e,$==f;$"++for+ab..an;@"=qw,u t,,print+chr;sub f{split}say"@{=} me"'

View full thread Maske Regex