Thread Mehrere verschachtelte Begriffe in einem String verändern (8 answers)
Opened by Gast at 2008-12-05 09:42

murphy
 2008-12-05 22:14
#116863 #116863
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Gast+2008-12-05 18:08:54--
[...] Den Hinweis von murphy mit den Positionsintervallen werde ich mal in einer ruhigen Minute nachgehen. [...]


Das ist eine ganz einfache Sache. Hier mal eine beispielhafte Implementation – nicht sehr effizient, da man die Intervalle schlauer speichern könnte, aber sie funktioniert einwandfrei:
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
#
# Mark ranges in a string that match certain regular expressions
#
use 5.010;

use strict;
use warnings;

use List::Util qw/reduce/;
use List::MoreUtils qw/part/;

use constant {
    PATTERNS   => [ qr/gefall/, qr/alle/, qr/len/ ],
    MARK_START => '<b>',
    MARK_END   => '</b>'
};

sub insert_range(\@$$) {
    my ($rng, $beg, $end) = @_;

    my ($dsj, $ovl) = part {
        ($_->[0] >= $beg and not $_->[0] >= $end) or
            ($_->[1] >= $beg and not $_->[1] >= $end) or
            0;
    } @{$rng};

    $dsj //= [ ];
    $ovl //= [ ];

    foreach my $_ (@{$ovl}) {
        $beg = $_->[0] if ($_->[0] < $beg);
        $end = $_->[1] if ($_->[1] > $end);
    }

    @{$rng} = sort {
        $a->[0] <=> $b->[0];
    } @{$dsj}, [ $beg, $end ];
}

sub find_ranges($) {
    my ($str, @pat) = @_;
    my @rng = ();

    foreach my $pat (@{PATTERNS()}) {
        while ($str =~ m/$pat/g) {
            insert_range @rng, $-[0], $+[0];
        }
    }

    return @rng;
}

sub split_ranges($@) {
    my ($str, @rng) = @_;
    my ($pos, @pcs) = (0);
    my $_;

    foreach (@rng) {
        if ($pos < $_->[0]) {
            push @pcs, [ 0, substr $str, $pos, $_->[0] - $pos ];
        }
        push @pcs, [ 1, substr $str, $_->[0], $_->[1] - $_->[0] ];
        $pos = $_->[1];
    }

    if ($pos < length($str)) {
        push @pcs, [ 0, substr $str, $pos, length($str) - $pos ];
    }

    return @pcs;
}

sub mark_ranges(@) {
    reduce {
        if ($b->[0]) {
            $a . MARK_START . $b->[1] . MARK_END;
        }
        else {
            $a .= $b->[1];
        }
    } '', @_;
}

my $_;
while (<DATA>) {
    chomp;
    $_ = mark_ranges split_ranges $_, find_ranges $_;
    say;
}

__DATA__
Wir alle sind auf den Witz hereingefallen.
When C++ is your hammer, every problem looks like your thumb.

View full thread Mehrere verschachtelte Begriffe in einem String verändern