Avatar billede themepark Nybegynder
21. juli 2006 - 20:25 Der er 35 kommentarer og
2 løsninger

Regexp der ikke tillader samme bogstav mere end én gang

Jeg har prøvet at lave et regexp, der tjekker en liste med strenge, adskilt af linjeskift, og hvis strengen udelukkende består af bogstaver forskellige fra hinanden, skal det være en match, ellers ikke. Men det er ikke lykkedes mig, så jeg håbede at få lidt hjælp herinde.

Det vil f.eks. sige at data ikke skal matche, men at dato skal matche. Der befinder sig kun bogstaver i strengene, så det er alt jeg skal tjekke på.
Avatar billede nielle Nybegynder
21. juli 2006 - 20:28 #1
Hvis en af dine strenge matcher:

([a-z]).*\1

- så er der et bogstav i dublet.
Avatar billede themepark Nybegynder
21. juli 2006 - 20:32 #2
Men den matcher jo hvis der ER dubletter, den skal jo netop gøre det modsatte.
Avatar billede nielle Nybegynder
21. juli 2006 - 20:35 #3
Uhm, er tricket så ikke bare at sige at *hvis* den matcher, så er den ulovlig?
Avatar billede themepark Nybegynder
21. juli 2006 - 20:38 #4
Nej, for jeg bruger EditPadPro, så jeg skal have markeret alle de strenge, der ikke indeholder dubletter. Så på en eller anden måde skal jeg have "negated" mit udtryk, men det er netop der jeg har mit problem :-S
Avatar billede nielle Nybegynder
21. juli 2006 - 20:48 #5
Så prøv med denne negerede version:

^((?!([a-z]).*\1).)$
Avatar billede themepark Nybegynder
21. juli 2006 - 20:53 #6
Den matcher kun strenge med 1 tegn?! :-S
Avatar billede nielle Nybegynder
21. juli 2006 - 21:04 #7
Min fejl. Sådan:

^((?!([a-z]).*\1).)*$
Avatar billede themepark Nybegynder
21. juli 2006 - 21:06 #8
Den matcher så til gengæld alt, både bogstaver og tal :(
Avatar billede nielle Nybegynder
21. juli 2006 - 21:08 #9
Den matchere vel ikke "alt" ... f.eks. ikke linjer med dublet-bogstaver.
Avatar billede themepark Nybegynder
21. juli 2006 - 21:09 #10
Jo lige præcis, tal, bogstaver, alle linjer hvad enten der er dubletter eller ej, kort sagt alt.
Avatar billede nielle Nybegynder
21. juli 2006 - 21:14 #11
Det gør den altås ikke hos mig?!

Men prøv denne som skulle indskrænke til kun at tillade bogstaver:

^((?!([a-z]).*\1|[^a-z]).)*$
Avatar billede _darkstar_ Nybegynder
21. juli 2006 - 21:29 #12
Jeg går ud fra at dette er et eksempel på en dublet-streng:

aarhus

Men er dette her også en dublet?

odense
Avatar billede _darkstar_ Nybegynder
21. juli 2006 - 21:29 #13
...og skal man skelne imellem små og store bogstaver? Er Aarhus en dublet-streng eller ej?
Avatar billede themepark Nybegynder
21. juli 2006 - 21:41 #14
Yep darkstar, odense ville også være en dublet. Og det med små og store bogstaver har ingen betydning, som nævnt bruger jeg EditPad Pro, som standard skelner den ikke mellem store og små bogstaver, uanset om jeg bruger [A-Za-z] eller [A-Z] :)

nielle, samme resultat :( Hvilket program bruger du til at tjekke det med?
Avatar billede nielle Nybegynder
21. juli 2006 - 21:44 #15
Jeg tjekker i C# men ifølge Reg Edit Pro forfatterens egne ord så er REP fuldstændig kompatibel med den regex variant som bruges af .Net.

Og når han selv siger det så er jeg tilbøjelig til at tro på det, for det er *skisme* en man som ved noget om regex'es! Det er f.eks. ham som står bag http://www.regularexpressions.info og RegBuddy.
Avatar billede nielle Nybegynder
21. juli 2006 - 21:47 #16
... RegexBuddy.
Avatar billede themepark Nybegynder
21. juli 2006 - 21:51 #17
Det er netop også den side, jeg har kigget på, og derigennem jeg fandt EditPad Pro. Og jeg kan da se at at delen om regexp i hjælp filen er magen til den på sitet, så jeg formodede da at han også var manden bag REP.

Men så forstår jeg overhovedet ikke hvor det går galt, blot at alle linjer, inklusive den linje med et enkelt ciffer, men ekslusive de linjer der består kun af cifre, men mere end 1, alle bliver highlightet.
Avatar billede themepark Nybegynder
21. juli 2006 - 21:54 #18
Hov, linjen med det enkelte ciffer bliver heller ikke markeret, jeg havde ikke indsat dit nyeste regexp.
Avatar billede nielle Nybegynder
21. juli 2006 - 21:54 #19
Kan du ikke lige poste dine eksempler her og vise hvilke der bliver highlightet (matcher) og hvilke der ikke bliver?
Avatar billede themepark Nybegynder
21. juli 2006 - 22:00 #20
Data
837
222
833337
data
Data
data
Data
A
a
b
b
AA
aa
data
Data
abe
Abe
Ab
8
Bb
AAA
date
Abba
Alternative
Iraqi
quit

De 4 linjer med cifrene bliver IKKE highlightet, men resten gør.
Avatar billede nielle Nybegynder
21. juli 2006 - 22:31 #21
Fandt en fejl i den forrige. Denne burde være mere korrekt:

^((?!(([a-z]).*\1|[^a-z])).)*

Dog fejler den hos mig med alle linjer på formen "aa", og jeg kan ikke rigtigt knække den. :^|
Avatar billede themepark Nybegynder
21. juli 2006 - 23:47 #22
Hvilket i REP blot giver at de selv samme linjer fra før får deres første bogstav highlightet og intet andet :( Jeg tror jeg bliver nødt til at kigge den tutorial grundigt igennem, for jeg SKAL have det til at virke i REP, at det virker i C# eller andet hjælper mig overhovedet ikke :(
Avatar billede _darkstar_ Nybegynder
22. juli 2006 - 00:05 #23
Hvis odense også tæller som en dublet-streng, tvivler jeg meget kraftigt på at det kan lade sig gøre. Nielles regex ser ikke ud til at være standard. Hvad betyder \1? Kan du henvise til noget dokumentation?
Avatar billede themepark Nybegynder
22. juli 2006 - 00:21 #24
\1 er det, der andetsteds hedder $1, altså en reference til den karakter den er nået til ([a-z]). Standard eller ej, bare det virker i REP er jeg glad :D
Avatar billede themepark Nybegynder
22. juli 2006 - 00:28 #25
Jeg opdagede lige at der manglede et $ i dit seneste regexp, nielle. Med den tilføjet er resultatet desværre som før, alle linjer pånær cifrene bliver highlightet :(
Avatar billede _darkstar_ Nybegynder
22. juli 2006 - 01:10 #26
Så lærte jeg også noget nyt. Det ser endda ud til at være med i perl. Dælme.

Hvad med denne her:

^(?!([[:alpha:]])[[:alpha:]]*\1[[:alpha:]]*)[[:alpha:]]*$

Stort set det samme som nielle, men blot pænificeret lidt.
Avatar billede _darkstar_ Nybegynder
22. juli 2006 - 01:12 #27
Sorry. Her er den:

^(?![[:alpha:]]*([[:alpha:]])[[:alpha:]]*\1[[:alpha:]]*)[[:alpha:]]*$

Så kunne man alligevel.

Jeg får disse linier fra dine eksempler:
A
a
b
b
abe
Abe
Ab
Bb
date
Iraqi
quit
Avatar billede _darkstar_ Nybegynder
22. juli 2006 - 01:13 #28
Men igen - det ovenstående er vanvittigt dyrt at køre. Det betaler sig langt bedre at skrive en stump kode, som udfører arbejdet.
Avatar billede nielle Nybegynder
22. juli 2006 - 09:03 #29
21/07-2006 23:47:17> Hvorfor SKAL det gøres i EditPad Pro? Bare af ren nysgerrighed.

I mellemtiden har jeg så installeret EPP, og jeg må tilstå at jeg heller ikke kan få det til at fungere. Nu er jeg efterhånden parat til at smide håndklædet i ringen. Jeg ved ikke om det hjælper at læse manualen endnu engang (ellers kig efter "negativ lookaround"), for det er netop det jeg har forsøgt at gøre (godt nok i hans bog i stedet for EPP's manual).

22/07-2006 00:05:35> Nu er der faktisk ikke noget som hedder standard inden for regex'es. Hvert programmeringssprog (og editor) har sin egen smagsvariant af hvordan de er implementeret. Når det så er sagt så er \1 altså en af de ting som er med i stort set hver eneste regex-variant.

Desuden bruger min regex negativ lookahead, og en regex-motor som understøtter dette har ihvertfald også \1.

22/07-2006 00:21:33> Nej, $1 og \1 er nu ikke helt det samme. \1 bruges til backtracking, og $1 bruges i forbindelse med at man har brug for at udtrække værdien af en grouping, f.eks. i forbindelse med en replace.

22/07-2006 00:28:07> Beklager den med det manglende $ - det var en dum cut'n'paste fejl.

22/07-2006 01:10:17> Så vidt jeg husker er [:alpha:] bare en anden måde at skrive a-z på? Jeg må indrømme at jeg aldrig selv har set nogen større grund til at bruge den (eller dens søskene).
Avatar billede themepark Nybegynder
22. juli 2006 - 11:36 #30
darkstar, jeg ændrede :alpha: til a-z og fjernede den en [] i hvert udtryk, og så virkede det tilsyneladende (jeg har ikke tænkt mig at løbe hvert eneste ord igennem for at sikre mig at det virker 100 % :-P). Og jeg prøvede at minimere det lidt, og kunne i hvert fald fjerne den 4. alpha plus *, så mit udtryk blev således.

^(?![a-z]*([a-z])[a-z]*\1)[a-z]*$

Men kan du forklare mig hvordan det fungerer? Jeg forstår ikke hvorfor der skal være så mange [a-z]* i det regex.

nielle, jeg laver det i EPP (ikke REP, my bad) grundet dette indlæg:

http://www.eksperten.dk/spm/721511

Jeg blev anbefalet at bruge en tekst editor i stedet for, og faldt over EPP, som jo også har været ganske fortrinlig til dette :) Men jeg er da glad for at det ikke bare er fordi jeg er dum, at det var problematisk at få til at virke i EPP :-P

Mht. forskellen mellem $1 og \1, sandt nok, min fejl.

Jeg kan se at jeg vist alligevel skal kigge den tutorial igennem, regex udtryk har altid forvirret mig mere end godt er, således også i dette tilfælde.
Avatar billede _darkstar_ Nybegynder
22. juli 2006 - 12:29 #31
Som du kan se af mit svar så testede jeg mit forslag (i perl) og det virkede fint. [:alpha:] er standard, men det virker åbenbart ikke i dit miljø.

Den næstsidste [[:alpha:]]* var overflødig, så det er helt korrekt at du har fjernet den.

Det hele betyder:


^ match start af strengen
(?! udtrykket efter denne parantes må kun matche hvis det ikke starter med det som er indeni parantesen
[[:alpha:]]* nogle bogstaver
([[:alpha:]]) et bogstav som vi husker (i \1)
[[:alpha:]]* nogle bogstaver
\1 det bogstav som vi huskede tidligere
[[:alpha:]]* nogle flere bogstaver (dette led kan udelades)
)[[:alpha:]]* nogle flere bogstaver
$ strengens slutning

Princippet er det samme for din version, men bemærk at [a-z] kun matcher lige præcis a til z, hvor [:alpha:] med de rigtige indstillinger også matcher sjove bogstaver, som é, æ, ö og den slags.
Avatar billede nielle Nybegynder
22. juli 2006 - 14:54 #32
Heh, du behøver ikke at undskylde for at du har skrevet REP ... det var mig som kom til at indføre den "forkortelse" tilbage i 21/07-2006 21:44:59. My bad. :^)

Løsningen fra 22/07-2006 11:36:20 kan iøvrigt forkortes til:

^(?!.*([a-z]).*\1)[a-z]*$

- eller endda til:

^(?!.*(.).*\1)[a-z]*$

(og den dur faktisk også i C# ;^)


Jeg skal gerne forsøge at forklare den:

^ og $ - er ankre til hhv. start og slut af strengen. De sikre at matchningen sker på hele linjer.

(?! ... ) - er "negativ lookahead". Den matcher noget som ikke er efterfulgt af det der står på "..." pladsen.

Når der altså står:

^(?! ... ) - så matcher den starten af linjen blot denne ikke er efterfulgt af "...".

Det der står på "..." pladsen:

.*(.).*\1

- eller splittet op i dens enkelte led:

.* (.) .* \1 - matcher 0 eller flere tegn, derefter ét tegn som bliver fanget af ()-gruppen, derefter 0 eller flere tegn og så til sidst noget som er lig med det som blev fanget tidligere i forløbet af ()-gruppen. Det matcher med andre ord noget som er en dublet (den dublet er i øvrigt ikke bundet til at være et bogstav).

Hvis det indsættes i vores negative lookahead:

^(?!.*(.).*\1) - matcher det starten af en linje, hvis der ikke efterfølgende er en dublet. Den allerførste ".*" i ".*(.).*\1" skal være med for at tage højde for at dubletten jo kan ligge inde i linjen, i stedet for i starten. Det er vigtigt at have den hvis vi skal bruge udtrykket sammen med vores negative lookahead og ^-ankret.

Den sidste [a-z]*:

^(?!.*(.).*\1)[a-z]*$ - er med for at fylde ud til enden af strengen. Den har dog også den vigtige funktion at den sørger for at regex'en ikke matcher med noget som helst andet end bogstaver.

Håber at det kastede lys over det?
Avatar billede _darkstar_ Nybegynder
23. juli 2006 - 22:33 #33
Lukketid?
Avatar billede nielle Nybegynder
28. juli 2006 - 09:07 #34
Hmm?
Avatar billede themepark Nybegynder
29. juli 2006 - 23:55 #35
Ja sorry, men jeg har ikke tjekket min mail i et stykke tid :(

nielle, smid et svar, den forklaring er jo guld værd :D Jeg forstår oven i købet nu hvorfor jeg kunne fjerne den 4. [a-z] fra det regex.

Men et lille tillægs spørgsmål. Ville den regex ikke også kunne matche en tom linje, altså bare et linjeskift pga [a-z]*, altså 0 eller flere forekomster af bogstaver? Eller er jeg helt gal på den?
Avatar billede nielle Nybegynder
30. juli 2006 - 08:05 #36
> Eller er jeg helt gal på den?

Nej, det er helt rigtigt. :^)

... og et svar :^)
Avatar billede nielle Nybegynder
02. august 2006 - 06:47 #37
Takker for point :^)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester