[PERL] probleem met regex

Pagina: 1
Acties:
  • 128 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • DPLuS
  • Registratie: April 2000
  • Niet online
Ik heb de volgende code:

code:
1
2
3
4
5
6
7
8
#!/usr/bin/perl -w
open FH, "meta_new_utf8" or die "Unable to open File\n";
while (<FH>) {
    chomp;
    print $_ . "\n" if /^am.*foort/;
}
close FH;
exit 0;


Dit staat er o.a. in het meta_new_utf8 bestandje:

amersfoort
amsterdam


Nu wil ik met mijn regex alles selecteren dat met am begint (^am) maar als er foort in voorkomt moet 'ie het niet meenemen.
En dat laatste lukt me dus niet.
Ik dacht zelf aan: /^am.*[^(foort)]/ maar dat pakt 'ie dus niet.
Hoe kan ik in die regex aangeven dat 'ie woorden waar foort in voorkomt niet moet meenemen?

Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
Het makkelijkst is natuurlijk om er twee regexen van te maken. ;)

Maar ik zal nog even nadenken over een oplossing met één regex.

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Je was warm. Bij mij werkt de volgende correct:
^am.*[^(foort)]$

Aanname is dat er per regel een plaatsnaam staat.

[ Voor 28% gewijzigd door Niemand_Anders op 06-12-2007 10:51 ]

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 14-09 14:16
DPLuS schreef op donderdag 06 december 2007 @ 10:29:
Ik heb de volgende code:

code:
1
2
3
4
5
6
7
8
#!/usr/bin/perl -w
open FH, "meta_new_utf8" or die "Unable to open File\n";
while (<FH>) {
    chomp;
    print $_ . "\n" if /^am.*foort/;
}
close FH;
exit 0;


Dit staat er o.a. in het meta_new_utf8 bestandje:

amersfoort
amsterdam


Nu wil ik met mijn regex alles selecteren dat met am begint (^am) maar als er foort in voorkomt moet 'ie het niet meenemen.
En dat laatste lukt me dus niet.
Ik dacht zelf aan: /^am.*[^(foort)]/ maar dat pakt 'ie dus niet.
Hoe kan ik in die regex aangeven dat 'ie woorden waar foort in voorkomt niet moet meenemen?
Zoiets?

#!/usr/bin/perl -w
open FH, "am.data" or die "Unable to open File\n";
while (my $text = <FH>) {
chomp($text);
print $text . "\n" if $text =~ /^am.*/ && $text !~ /foort/;
}
close FH;
exit 0;

Acties:
  • 0 Henk 'm!

  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 14-09 14:16
Niemand_Anders schreef op donderdag 06 december 2007 @ 10:50:
Je was warm. Bij mij werkt de volgende correct:
^am.*[^(foort)]$

Aanname is dat er per regel een plaatsnaam staat.
Dat is meer geluk dan wijsheid, omdat amsterdam eindigt op een letter die niet in foort zit denk ik.
Probeer 'amsterdat' eens uit zou wel gematcht moeten worden, doet het niet?!

Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
Je maakt een character class dus de letters staan op zichzelf.

Zoiets?
code:
1
/^am.*(?!foort).*$/


Eventueel nog wat spelen met greediness. :)

[ Voor 18% gewijzigd door Gonadan op 06-12-2007 11:19 ]

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

code:
1
^am.*(?!foort)$

Zoiets misschien? Mijn regex-kennis is wat stoffig, maar dat zou volgens mij moeten werken. :P
edit:
Anders is Gonadan me even voor. :P

[ Voor 15% gewijzigd door NMe op 06-12-2007 11:21 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • DPLuS
  • Registratie: April 2000
  • Niet online
Eigenlijk zoek ik een regex die deze constructie in 1 regex zet:

code:
1
print $text . "\n" if $text =~ /^am/ && $text !~ /foort/;

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

...en die gaven Gonadan en ik je net?

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
-NMe- schreef op donderdag 06 december 2007 @ 11:32:
...en die gaven Gonadan en ik je net?
Idd, zoek even naar lookahead en lookbehind, reuze handige opties in een regex. :)

@-NMe- hieronder:
copuleerder der Formicidae!
je hebt ook nog positive en negative lookahead en lookbehind assertions om precies te zijn ;)

[ Voor 23% gewijzigd door Gonadan op 06-12-2007 11:38 ]

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Gonadan schreef op donderdag 06 december 2007 @ 11:33:
[...]

Idd, zoek even naar lookahead en lookbehind, reuze handige opties in een regex. :)
Lookahead en lookbehind assertions om helemaal precies te zijn. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • DPLuS
  • Registratie: April 2000
  • Niet online
-NMe- schreef op donderdag 06 december 2007 @ 11:32:
...en die gaven Gonadan en ik je net?
Die doen het alle 2 niet bij mij (Debian Etch, Perl 5.8.8)

Perl:
1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/perl -w
open FH, "meta_new_utf8" or die "Unable to open File\n";
while (my $text = <FH>) {
    chomp($text);
#   print $_ . "\n" if /^am(?!s)/; #amsterdam, amersfoort
#   print $text . "\n" if $text =~ /^am/ && $text !~ /foort/;
    print $text . "\n" if $text =~ /^am.*(?!foort).*$/;

}
close FH;
exit 0;

Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
DPLuS schreef op donderdag 06 december 2007 @ 11:37:
Die doen het alle 2 niet bij mij (Debian Etch, Perl 5.8.8)
De versie van je OS zou niets uit moeten maken. ;)

Wat ik al zei, probeer eens met greediness te werken en zoek zelf even naar deze termen.
Het is natuurlijk niet de bedoeling dat wij de regex voor je gaan schrijven. ;)

Wat doet hij precies wel en niet bij de regexen van -NMe- en mij?

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • DPLuS
  • Registratie: April 2000
  • Niet online
Bij de bovenstaande code krijg ik zowel amsterdam als amersfoort als output.

Ik heb werkelijk al uren gezocht naar een manier om een string aan karakters te "negaten" in een regex.

In een characterclass is het heel simpel: [^0-9], waarom bestaat er nu zoiets ook niet voor een string??


PS: Die lookaheads werken op het eerste gezicht ook alleen maar met single chars: http://www.regular-expressions.info/lookaround.html

[ Voor 19% gewijzigd door DPLuS op 06-12-2007 11:46 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

DPLuS schreef op donderdag 06 december 2007 @ 11:45:
In een characterclass is het heel simpel: [^0-9], waarom bestaat er nu zoiets ook niet voor een string??
Dat bestaat wel, negative lookahead assertions, oftewel "(?!string)". Er gaat hier iets anders mis, en ik gok dat dat met greediness te maken heeft. Probeer deze eens:
code:
1
/^am.*?(?!foort)$/

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
http://www.perl.com/doc/manual/html/pod/perlre.html
http://www.perl.com/pub/a/2003/07/01/regexps.html
-NMe- schreef op donderdag 06 december 2007 @ 11:47:
[...]

Dat bestaat wel, negative lookahead assertions, oftewel "(?!string)". Er gaat hier iets anders mis, en ik gok dat dat met greediness te maken heeft. Probeer deze eens:
code:
1
/^am.*?(?!foort)$/
Volgens mij kan je quantifiers niet stacken. :)
Wel dus :+

[ Voor 65% gewijzigd door Gonadan op 06-12-2007 11:51 ]

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Greedy and Ungreedy Matching
Perl regular expressions normally match the longest string possible. For instance:

my($text) = "mississippi";
$text =~ m/(i.*s)/;
print $1 . "\n";

Run the preceding code, and here's what you get:

ississ

It matches the first i, the last s, and everything in between them. But what if you want to match the first i to the s most closely following it? Use this code:

my($text) = "mississippi";
$text =~ m/(i.*?s)/;
print $1 . "\n";

Now look what the code produces:

is

Clearly, the use of the question mark makes the match ungreedy.
:P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
offtopic:
Vond het al in de eerste link die ik zelf gepost had. :+
Je bent een beetje spuit11erig vandaag hè? Koffie? ;)

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • DPLuS
  • Registratie: April 2000
  • Niet online
Ik krijg ze nog altijd allemaal terug.

Even voor mijn beeldvorming:

code:
1
print $text . "\n" if $text =~ /.*(?!foort).*/;


Dit zou toch moeten betekenen dat alle regels met de string "foort" NIET matchen?
M.a.w. als ik amsterdam, amersfoort en amersfoortse zou hebben, zou alleen amsterdam ge-output moeten worden, toch?

Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
DPLuS schreef op donderdag 06 december 2007 @ 12:00:
Ik krijg ze nog altijd allemaal terug.

Even voor mijn beeldvorming:

code:
1
print $text . "\n" if $text =~ /.*(?!foort).*/;


Dit zou toch moeten betekenen dat alle regels met de string "foort" NIET matchen?
M.a.w. als ik amsterdam, amersfoort en amersfoortse zou hebben, zou alleen amsterdam ge-output moeten worden, toch?
Niet echt, want je geeft niet aan welk deel van de string je wilt matchen.
Nu hoeft er maar een klein deel van de string geen 'foort' te bevatten om te matchen.
Daarom geef ik graag zelf aan dat het om de hele string gaat, dus met ^$ erbij.
Dan zou het inderdaad zo moeten werken volgens mij.

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 14-09 14:16
Gonadan schreef op donderdag 06 december 2007 @ 11:57:
[...]

offtopic:
Vond het al in de eerste link die ik zelf gepost had. :+
Je bent een beetje spuit11erig vandaag hè? Koffie? ;)
testen jullie je antwoorden?
Niet dat ze niet enorm leerzaam zijn, maar deze werkt wèl:

print $text . "\n" if $text =~ /^am(?!(.*foort))/;

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Laten we eens een lookbehind proberen:
code:
1
/^am.*(?<!foort)$/
pkuppens schreef op donderdag 06 december 2007 @ 12:15:
[...]

testen jullie je antwoorden?
Is dat per se nodig om te kunnen helpen dan? Sure, het helpt wel, maar ik heb hier geen perl draaien. Is mijn antwoord daarom waardeloos? ;)
Niet dat ze niet enorm leerzaam zijn, maar deze werkt wèl:

print $text . "\n" if $text =~ /^am(?!(.*foort))/;
Die zou inderdaad ook moeten werken, ja. :)

[ Voor 77% gewijzigd door NMe op 06-12-2007 12:17 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Laatst online: 22:16

Gonadan

Admin Beeld & Geluid, Harde Waren
pkuppens schreef op donderdag 06 december 2007 @ 12:15:
[...]


testen jullie je antwoorden?
Niet dat ze niet enorm leerzaam zijn, maar deze werkt wèl:

print $text . "\n" if $text =~ /^am(?!(.*foort))/;
Ik ben aan het testen ja maar die van jou werkt ook niet hoor.
Het probleem is dat die .* alles wel matcht, ook al zit foort er bij, ik knutsel nog even met greediness. ;)

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 14-09 14:16
Gonadan schreef op donderdag 06 december 2007 @ 12:20:
[...]

Ik ben aan het testen ja maar die van jou werkt ook niet hoor.
Het probleem is dat die .* alles wel matcht, ook al zit foort er bij, ik knutsel nog even met greediness. ;)
Hmm, daar was is al bang voor, compatibiliteits issues?
Hier werkt 'ie:

~ % perl -v

This is perl, v5.6.1 built for sun4-solaris

~ % cat am.data
amsterdam
amsterdat
amersfoort
amersafoorti

~ % cat am.pl
#!/usr/bin/perl -w
open FH, "am.data" or die "Unable to open File\n";
while (my $text = <FH>) {
chomp($text);
print $text . "\n" if $text =~ /^am(?!(.*foort))/;
}
close FH;
exit 0;

~ % perl am.pl
amsterdam
amsterdat

~ %

PS. met sed doet 'ie het niet :'(

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:39
Dit soort uitzonderingen kun je met (standaard) reguliere expressies niet goed beschrijven. Je moet dan iets doen van de vorm:
code:
1
^am([^f]|f([^o]|o([^o]|o([^r]|r[^t]))))*$

Lees dit als: eerst am, en dan een willekeurig aantal keer géén f, óf (een f gevolgd door (geen o, of een o gevolgd door (geen o ... ) ) ) etcetera. Ontzettend vervelend om met de hand te schrijven en ook om te lezen.

Ik zeg dit geloof ik in elk topic over reguliere expressies, maar toch: je moet RE's niet overgebruiken. Ze kunnen hardstikke handig zijn om snel reguliere patronen te matchen, maar als je patroon niet duidelijk regulier te beschrijven is, dan kun je beter terugvallen op andere mechanismen die de taal je biedt. Er is niets mis met het gebruik van twee reguliere expressies of het combineren van reguliere expressies met andere stringmanipulatiesfuncties (het is in ieder geval beter dan je patroon te omschrijven als een gigantische onleesbare reguliere expressie).

edit:
Bovenstaande RE werkt trouwens ook niet goed, omdat je nu een string als "amffoort" wel accepteert. De subexpressies moeten eigenlijk lookaheads zijn (dan klopt het wel) maar dat is dus weer geen standaardfeature. Liever helemaal niet in één RE doen dus.

[ Voor 12% gewijzigd door Soultaker op 06-12-2007 17:23 ]

Pagina: 1