Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]10623[/thread]

regex automatisch erstellen

Leser: 1


<< >> 7 Einträge, 1 Seite
kristian
 2007-10-20 19:09
#101135 #101135
User since
2005-04-14
684 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo

Ich versuche automatisiert regex zu erstellen, die ich dann in eine Datei schreibe.
Ich will den Bereich zwischen zwei Zahlen matchen.
Beispiel:
Bereich 28 -> 31 => m/(28|29|30|31)/
Dies mache ich hier einfach mit $string = 'm/(' . join("|", ($first_number..$last_number)) . ')/'
Bei grösseren Bereichen wird der String natürlich sehr lang.
Ich hätte lieber: m/(2[8-9]|3[0-1])/

oder anderes Beispiel:
Bereich 128 -> 255 =>
m/(128|129|130|131|132| [..usw..] 249|250|251|252|253|254|255)/
soll sein:
m/(12[8-9]|1[3-9][0-9]|2[0-4][0-9]|25[0-5])/

Es soll universell für Zahlenbereiche funktionieren, die zwischen 0 und 255 liegen.
Mir ist auch klar, dass die regex vor der Ausführung wieder durch den langen String repräsentiert wird und das Kürzen nicht wirlich CPU-freundlich ist, allerdings will ich in der Datei den Ball flach halten.

Hat eine(r) ne Idee, wie ich das hinbekommen könnte?

TIA
Kristian
Relais
 2007-10-20 20:40
#101136 #101136
User since
2003-08-06
2254 Artikel
ModeratorIn
[Homepage] [default_avatar]
Besser als Regex alleine ist da eine Kombination aus
/(\d+)/ and $lower <= $1 and $upper >= $1
Erst denken, dann posten --
27. Deutscher Perl- u. Raku -Workshop 12. bis 14. Mai 2025 in München.

Winter is Coming
kristian
 2007-10-20 21:15
#101138 #101138
User since
2005-04-14
684 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo

Das klappt hier leider nicht.
Das Programm, welches die Datei verarbeitet ist nicht in Perl geschrieben und erwartet eine Regex, wobei der Syntax ein Mix aus C- und Perl-Regex ist.

Ich werde, wenn keiner eine geniale Idee hat, wohl erst die Sonderfälle am Anfang und Ende des Bereiches abarbeiten und dann den verbleibenden Mittelteil angehen, wobei ich da eigentlich nur noch int(100) berücksichtigen muss, zumindest denke ich mir das im Moment so.

Gruss
Kristian
kristian
 2007-10-20 22:28
#101139 #101139
User since
2005-04-14
684 Artikel
BenutzerIn
[Homepage] [default_avatar]
Code der bislang zu funktionieren scheint:
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
sub _create_regex_block($$){
    my $first_number = shift;
    my $last_number  = shift;

    return $first_number if($first_number == $last_number);

    my ($string,@first_digits,@last_digits,$first_block,$last_block,$ctrl_number,@blocks,$this_block,$last_block_number);

    @first_digits = split(//,$first_number);
    @last_digits  = split(//,$last_number);

    if($first_digits[$#first_digits] != 0){
        $ctrl_number = join("", @first_digits[0..($#first_digits - 1)], 9);
        $ctrl_number += 0;
        if($ctrl_number > $last_number){
            $first_block = (($#first_digits)? join("", @first_digits[0..($#first_digits - 1)]) : '')  . '[' . $first_digits[$#first_digits] . '-' . $last_digits[$#last_digits] . ']';      
            return $first_block;
        }else{
            $first_block  = (($#first_digits)? join("", @first_digits[0..($#first_digits - 1)]) : '')  . '[' . $first_digits[$#first_digits] . '-9]';
            $first_number = (int($first_number / 10) * 10 ) + 10;
        }
    }

    if($last_digits[$#last_digits] != 9){
        $last_block  = (($#last_digits)? join("", @last_digits[0..($#last_digits - 1)]) : '') . '[0-' . $last_digits[$#last_digits] . ']';
        $last_number = (int($last_number / 10) * 10 ) - 1;      
    }
    if($last_number > $first_number){
        if(length($first_number) == 1){
            if($first_number == $last_number){
                $this_block = $first_number
            }else{
                $last_block_number = 9;
                $last_block_number = $last_number if($last_block_number > $last_number);
                $this_block = '[' .  $first_number . '-' . $last_block_number . ']';
                $first_number = 10 if($last_number >= 10);
            }
            push(@blocks, $this_block);
        }
        if(length($first_number) == 2){
            if($first_number == $last_number){
                $this_block = $first_number
            }else{
                @first_digits = split(//,$first_number);
                $last_block_number = 99;
                $last_block_number = $last_number if($last_block_number > $last_number);
                @last_digits  = split(//,$last_block_number);
                if($first_digits[0] == $last_digits[0]){
                    $this_block = $first_digits[0] . '[' . $first_digits[1]  . '-' . $last_digits[1] . ']';
                }else{
                    $this_block = '[' . $first_digits[0]  . '-' . $last_digits[0] . '][' . $first_digits[1]  . '-' . $last_digits[1] . ']';
                }
                $first_number = 100 if($last_number >= 100);
            }
            push(@blocks, $this_block);
        }
        if(length($first_number) == 3){
            if($first_number == $last_number){
                $this_block = $first_number
            }else{
                my $work_to_do = 1;
                while($work_to_do){
                    @first_digits = split(//,$first_number);
                    $last_block_number = (((int($first_number / 100) + 1) * 100) - 1); # 199 / 299
                    if($last_block_number >= $last_number){
                        $last_block_number = $last_number;
                        $work_to_do = 0;
                    }
                    @last_digits  = split(//,$last_block_number);
                    if($first_digits[1] == $last_digits[1]){
                        $this_block = $first_digits[0] . $first_digits[1] . '[' . $first_digits[2]  . '-' . $last_digits[2] . ']';
                    }else{
                        $this_block = $first_digits[0] . '[' . $first_digits[1]  . '-' . $last_digits[1] . '][' . $first_digits[2]  . '-' . $last_digits[2] . ']';
                    }
                    $first_number = ((int($last_block_number / 100) + 1) * 100);
                    $work_to_do = 0 if($first_number >= $last_number);
                    push(@blocks, $this_block);
                }
            }
        }
    }

    if(defined $first_block){
        unshift(@blocks, $first_block);
    }
    if(defined $last_block){
        push(@blocks, $last_block);
    }


    if(scalar(@blocks) > 1){
        $string = '(' . join('|', @blocks) . ')';
    }else{
        $string = $blocks[0];
    }

    return $string; 
}


EDIT:

Ich habe fertig.
Sieht nicht schön aus, scheint aber die Aufgabe zu lösen.
Ev. kann es ja mal eine(r) brauchen.

Gruss
Kristian
MisterL
 2007-10-21 12:31
#101143 #101143
User since
2006-07-05
334 Artikel
BenutzerIn
[default_avatar]
Code habe ich zwar keinen, aber dafür diese Idee für ein Eclipse Plugin (auf Java Basis): http://sourceforge.net/projects/quickrex

Gruss MisterL
“Perl is the only language that looks the same before and after RSA encryption.”
pq
 2007-10-21 14:54
#101148 #101148
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
wie wärs mit CPAN:Regexp::Assemble? sieht aus, als würde es genau das machen,
was du willst.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
kristian
 2007-10-21 16:20
#101154 #101154
User since
2005-04-14
684 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo

Code (perl): (dl )
1
2
3
4
use Regexp::Assemble;
my $ra = Regexp::Assemble->new;
$ra->add(127..254);
print $ra->re;

ergibt:
Code: (dl )
(?-xism:(?:1(?:2[789]|3\d|4\d|5\d|6\d|7\d|8\d|9\d)|2(?:5[01234]|0\d|1\d|2\d|3\d|4\d)))

Das ist zwar beeindruckend aber leider kein Syntax den ich brauchen kann.

Konkret, ich will von CIDR oder NetRange zu einer rexec, die ich mit mod_rewrite in einer .htaccess benutzen kann.

./to_regex 192.168.22.0/18
192.168.22.0/18 => RewriteCond %{REMOTE_ADDR} ^192\.168\.(2[2-9]|[3-7][0-9]|8[0-5])\.

ist die Ausgabe des mitlerweile fast fertigen Progs :-)

Danke & Gruss
Kristian
<< >> 7 Einträge, 1 Seite



View all threads created 2007-10-20 19:09.