Schrift
[thread]7502[/thread]

String in Sequenzen gleicher Zeichen zerlegen: mit Regex

Leser: 1


<< |< 1 2 >| >> 11 Einträge, 2 Seiten
pKai
 2005-11-28 15:42
#60482 #60482
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
In einen anderen Forum habe ich als Teil einer geposteten Lösung einen String in Ketten identischen Zeichen zerlegt.
also
Code: (dl )
'xx556xx' ---> qw(xx 55 6 xx)

Das beste was mir dazu als Regex eingefallen ist, war
Code: (dl )
my @Array = keys %{{$String =~ m/((.)\2*)/g}}
was schon deshalb irgendwie unschön ist, da ich die zusätzliche gelieferten $2 (\2) wieder ausfiltern muss (hier über den Weg array -> hash -> keys -> array).
Gibt es eine elegante(re) perlische Lösung (keine for-Schleife!)?
I sense a soul in search of answers.
pq
 2005-11-28 17:01
#60483 #60483
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
Code: (dl )
1
2
3
4
5
my %count;
my $max;
for (split //, $string) {
 $max = $count{$_} if ++$count{$_} > $max;
}

finde ich perlish genug. deine lösung mit sort ist relativ unperformant,
nur um das größte element zu finden.
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
murphy
 2005-11-28 17:13
#60484 #60484
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Mach das doch so, dann brauchst du keinen Hash:
Code: (dl )
1
2
my @x = "xx556xx" =~ m/((.)\2*)/g;
@x = map { $x[2*$_] } (0..@x/2-1);
When C++ is your hammer, every problem looks like your thumb.
pKai
 2005-11-28 17:47
#60485 #60485
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
@pq: das versteht jetzt aber keiner, der den andern Thread nicht kennnt ;)
Und darum ging es mir hier auch garnicht.
Threadsubject: "String in Sequenzen gleicher Zeichen zerlegen"
Unabhängig von einem möglichen Miss-/Gebrauch des Ergebnisses.

@murphy: War mir klar, dass das geht. Ich hatte die gezeigte Form nur bevorzugt, da ich es dann funktional in einer Anweisung weiterverarbeiten kann.

Ich erhoffe mir eher Hinweise/Anregungen für einen anderen Regex, der die Geschichte wenn möglich ohne weitere Nachverarbeitung bewerkstelligt.
I sense a soul in search of answers.
Taulmarill
 2005-11-28 17:50
#60486 #60486
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
irgendwie is das alles gebastle. wenn du einen sauberen ansatz suchst, würde ich dir raten, das als funktion/sub mit einem sprechenden namen auszulagern. in der sub kannst du dann in ruhe mit einer for- oder while-schleife durch den string gehen. das wird dann wesendlich lesbarer.
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
pKai
 2005-11-28 19:13
#60487 #60487
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Eigentlich bin ich eher auf der Suche nach der (mir) unbekannten Eigenschaft von Perl, die die Aufgabenstellung elegant und einfach löst.

"simple things easy, hard things possible"

Und die Aufgabenstellung sieht doch wirklich einfach genug aus, dass ich da keine Schleife, etliche Hilfsvariable und Vergleiche brauche ;)
I sense a soul in search of answers.
pKai
 2005-11-29 11:35
#60488 #60488
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Code: (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
use strict;
use warnings;
use Benchmark qw(:all);

my $s = 'xx55111111116jkwhcxxxxx';

sub test1 {
my $r;
my $r0;
my @R;
for my $c (split '', $s) {
unless (defined $r) {
$r = $c;
$r0 = $c;
} elsif($c eq $r0) {
$r .= $c;
} else {
push @R, $r;
$r = $c;
$r0 = $c;
}
}
push @R, $r if length $r;
@R;
}

sub test2 {
keys %{{$s =~ /((.)\2*)/g}}
}

sub test3 {
my @x = $s =~ m/((.)\2*)/g;
map $x[2*$_], 0..@x/2-1;
}

cmpthese (-20,
{
for => \&test1,
pKai => \&test2,
murphy => \&test3,
}
);

Code: (dl )
1
2
3
4
         Rate    for murphy   pKai
for 5172/s -- -12% -27%
murphy 5866/s 13% -- -18%
pKai 7123/s 38% 21% --


wobei "pKai" ausser Konkurrenz läuft, da der Hash-Trick nur klappt, wenn keine Sequenz mehrfach auftaucht und ausserdem die Reihenfolge nicht erhalten bleiben muss.

Die sub test1 hab ich mal naiv geschrieben, wie ich mir dachte, dass Perl das fix abarbeiten kann. Ging aber wohl in die Hose. Abgesehen davon, dass ich diese sub mitnichten verständlicher finden als murphys. Falls es eine einfachere (schnellere?) Version mit for gibt, interessiert mich das natürlich ;)
I sense a soul in search of answers.
pKai
 2005-11-30 01:08
#60489 #60489
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Da mich das Thema noch tiefer interessiert, habe ich mal bei den perlmonks gepostet.
Wen's ebenfalls interessiert bekommt in dem Thread dort und der darin verlinkten "Meditation" von Juni einiges an tiefgründiden Infos.
I sense a soul in search of answers.
pKai
 2005-12-01 00:20
#60490 #60490
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
(Bisheriges) Ergebnis der perlmonks-Diskussion:
Kürzeste Variante ist:
Code: (dl )
my @sequences = $string =~ m/((??{'(.)\1*'}))/g;

Die Geschwindigkeits kann noch erheblich verbessert werden, wenn der innere Regex vorkompliliert wird:
Code: (dl )
1
2
my $re = qr/(.)\1*/;
my @sequences = $string =~ m/((??{$re}))/g;

Diese Version ist in meinem Benchmark (gegenüber allen getesteten Varianten mit map, grep, while, for, etc; siehe oben und perlmonks-Thread) mit Abstand die schnellste.\n\n

<!--EDIT|pKai|1133389362-->
I sense a soul in search of answers.
Taulmarill
 2005-12-01 11:59
#60491 #60491
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
zu der (??{CODE}) funktion steht in der perldoc
Quote
WARNING: This extended regular expression feature is considered highly experimental, and may be changed or deleted without notice. A simplified version of the syntax may be introduced for commonly used idioms.

ist also ein netter hack, aber für produktiven code nicht zu gebrauchen.
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
<< |< 1 2 >| >> 11 Einträge, 2 Seiten



View all threads created 2005-11-28 15:42.