Gå til hovedindhold
Version2 it for professionelle
Forsiden

Hovedmenu

  • It-nyheder
  • Blogs
  • It-job
  • It-firmaer
  • Emner
  • Opret bruger
  • Log ind
Se kommentarer (36)
Emner

Regex kompetencer efterlyses (vind en t-shirt)

Af admin adminuser 1. oktober 2008 kl. 13:57

Min opmærksomhed er lige blevet fanget af det offentliges nye mega-repositorie, som er frontet af en Web 2.0 applikation.

Det ser jo lidt lækkert ud, men jeg har endnu ikke gravet dybt nok til en egentlig anmeldelse. Jeg fik dog set den nydelige og pædagogiske reklamefilm, som er på forsiden.

Der er noget lækkert GUI og en simuleret søgning efter artifakten "personnummer".

Jeg prøvede for sjov skyld at lave samme søgning og kom frem til en definition af personnummer, som jeg kunne genkende.

Kender I det at man får lavet noget som umiddelbart virkede ok, men som man, hvis man havde tid ville vende tilbage til og få optimeret!?

Sådan har jeg det med det regulære udtryk for personnummer, som jeg lavede for snart 7 år siden.

Jeg er sikker på at det kan laves bedre og jeg er villig til at udlodde en T-shirt for et det bedste regulære udtryk for personnummer, som bliver posted her i kommentarerne inden for de næste 30 dage.

Flest thumbs-up vinder!

Jeg håber at vinderen selv vil lægge en kommentar på digitaliser.dk med de foreslåede ændringer. 

Send Tweet
Udskriv
Om admin adminuserFollow @version2

Kommentarer (36)

Opret en konto eller log ind for at følge indhold på Version2 - og bliv opdateret via e-mail eller rss

Følg kommentarer
Peter Makholms billede
Peter Makholm 1. okt. 2008 - 15.15
 
Ét og kun ét regexp?

Jeg ville nok ikke række ud efter regulære udtryk som det eneste værktøj til en sådan opgave. Jeg ville nok trække datoelementerne ud med et regulært udtryk, men så finde en isValidDate() funktion fra værktøjskassen.

Et rigtigt regulært udtryk vil nemlig blive rigtig skummelt når der er en der opdager at udgangspunktet tillader 290207XXXX som CPR-nummer, skønt vi alle ved at denne dato ikke eksisterede.

En lavthængende frugt ville være at slå alle tal fra 10 til 29 sammen i et delelement. Altså erstatte de tre tilfælde af "1[0-9]|2[0-9]" med '[12][0-9]'.

Derudover ville jeg nok erstatte det ene tilfælde af '3[0-1]' med '30|31'. Det er lidt lettere at læse (IMHO), men nok hverken mere eller mindre effektivt.

Listen af måneder kan også komprimeres lidt, så 01, 03, 05, 07, 08, 10 og 12 bliver til (0[13578]|1[02])

Jeg tvivler dog noget på at vi kommer meget længere uden at anvende "smarte metoder", som man ikke altid kan være sikker på at have til rådighed. Altså bliver mit bedste bud:

((((0[1-9]|[12][0-9]|30|31)(0[13578]|1[02]))|((0[1-9]|[12][0-9]|30)(0[469]|11))|((0[1-9]|[12][0-9])(02)))[0-9]{6})|0000000000

Med smarte metoder tror jeg helle rikke vi når meget længere. Mit bedste bud på en "smart" forbedring ville være at bruge en "zero width negative look-ahead" til at angive at de to første tegn ikke må være 00. Så kan hver enkelt månedsdag angives med "(?!00)[012][0-9]|30|31". Ikke at det bliver meget kønnere, rent faktisk 3 tegn længere end ovenstående og sikkert uden at være mere effektiv.

Tror dog ærlig talt ikke at jeg har gjort udtrykket mere effektivt, og vil måske endda påstå at jeg har gjort det mere uigennemskueligt. Så min enedelige løsning ville nok være noget som kunen anvende en isValidDate()-funktion eller det oprindelige. Dog måske med min første forbedring for '1[0-9]|2[0-9]' blev slået sammen.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Esben Damgaard 1. okt. 2008 - 15.20
 
Kortere

Enig med Makholm om at validere en dato istedet for et regex, men er mit bud:

(([0-2]1-9)|(30(0[13-9])|1[0-2])|(31(0[13578]|1[02])))[0-9]{6}|0000000000

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Peter Makholms billede
Peter Makholm 1. okt. 2008 - 15.30
 
Re: Kortere

Kortere ja, men hvad matcher det egentlig? Da ikke et dansk personnummer, et svensk måske?

Desuden godkender det den kendte månedsdag 00.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Esben Damgaard 1. okt. 2008 - 15.39
 
Re: Kortere

Det matcher da danske..

Forklaring:

([0-2]1-9 Hvis dag < 30 må det være alle måneder.

|(30(0[13-9])|1[0-2]) Hvis dag == 30 kan det være alle måneder dog ikke 02

|(31(0[13578]|1[02])) Hvis dag == 31 kan det være månederne 01,03,05,07,08,10,12

[0-9]{6}|0000000000 alt det sidste.

Den genkender ikke måned 00. Prøv den af.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Peter Makholms billede
Peter Makholm 1. okt. 2008 - 15.43
 
Re: Kortere

Doh, jeg har været for længe på arbejde og springer i forvejen mellem forskellige datoformater. Hvis bare dog folk ville enes om ISO 8601...

Helt elendigt bliver det dog når samme standard beskriver at forskellige datoer skal angives med forskellige formater. suk (Nej, det er ikke en dokumentformatstandard jeg bander over)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Esben Damgaard 1. okt. 2008 - 15.48
 
Re: Kortere

ISO 8601 er bestemt også den jeg bedst kan lide :)

Men fandt lige en fejl i min regex. Den godkender ikke dag==10 eller 20. Mit nye regex bliver derfor:

((([0-2][1-9]|[12]0)(0[1-9]|1[0-2]))|(30(0[13-9])|1[0-2])|(31(0[13578]|1[02])))[0-9]{6}|0000000000

Det var også fordi jeg skulle skynde mig og komme med et bud, så blev den ikke testet så godt :)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Henrik Christian Grove 1. okt. 2008 - 15.51
 
Re: Kortere
([0-2][1-9](0[1-9]|1[0-2]) Hvis dag < 30 må det være alle måneder.

Og ikke den 10. eller 20.

|(30(0[13-9])|1[0-2]) Hvis dag == 30 kan det være alle måneder dog ikke 02

Du har en slutparentes for meget lige inden |.

[0-9]{6}|0000000000 alt det sidste.

Her mangler du så en slutparentes før |.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Esben Damgaard 1. okt. 2008 - 15.59
 
Re: Kortere

Ja, lidt parantes-fejl. Rettet giver det:

(((([0-2][1-9]|[12]0)(0[1-9]|1[0-2]))|(30(0[13-9]|1[0-2]))|(31(0[13578]|1[02])))[0-9]{6})|0000000000

Folk (inkl. mig selv..) tilfredse nu?

Release Early, Release Often som man siger... ;)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Torben Mogensens billede
Torben Mogensen 1. okt. 2008 - 15.59
 
Pas nu på!

På grund af mangel på CPR-numre, er man begyndt at bruge månedsnumre over 12 til midlertidige CPR-numre for udlændinge med kortere ophold i Danmark. Jeg husker ikke, hvilken konstant, man lægger til måneden for at få det til at passe.

Desuden bør et regulært udtryk for CPR-numre vel kontrollere, at check-cifret er korrekt, dvs. om den vægtede tværsum er delelig med 11.

Og, jo, det kan godt checkes af et regulært udtryk. Men det bliver ikke enkelt. :-)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Peter Makholms billede
Peter Makholm 1. okt. 2008 - 16.23
 
Re: Pas nu på!

Nej, erstatningspersonnumrene, hvor der er lagt 60 til månedsnummeret har ikke noget med mangel på personnumre at gøre. Det har altid været meningen at disse numre ikek skulle overlappe med de rigte CPR-numre. Et striks CPR-nummer-tjek bør dog kun tillade rigtige CPR-numre.

Modulo-11 tjekket er derimod officielt afskaffet, netop på grund af manglende personnumre. Derfor er en testrutine der anvender modulo-11 tjekket reelt set ukkorrekt.

Der er dog en grand af sandhed. En del af de datoer hvor der er mangel på CPR-numre der overholder modulo-11 tjekket, skyldes manglen netop indvandring hvor fødselsdatoen ikke vides med sikkerhed (elelr lignende).

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Kasper Henriksen 1. okt. 2008 - 17.24
 
Det her minder mig om noget...

Hvad kan det nu være det her spørgsmål minder mig om? Nåja, det gamle citat af Jamie Zawinski:

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems

( http://en.wikiquote.org/wiki/Jamie_Zawinski )

Hvorfor ikke bare kode noget, der leder efter ting af formen \d{7}-?\d{4} og så skrive en stump kode til at verificere, at det faktisk er en gyldig dato?

Forestil jer, at skulle tjekke for skudår med regular expressions.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Hans Schou 1. okt. 2008 - 19.00
 
Re: Ét og kun ét regexp?

Jeg har proppet udtrykket ind i kregexpeditor og den kommer ud med fejl når jeg bruger 21-10-62-5629 som test (født 1862). RegEx'en ser ellers rigtigt ud, så jeg ved ikke lige hvor det går galt.

Om ikke andet, så vil jeg anbefale kregexpeditor til dem der slås med regex.

Se screen dump her:
http://www.sslug.dk/~chlor/kregexpeditor/

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Kristian Thy 2. okt. 2008 - 00.27
 
Re: Det her minder mig om noget...
Nåja, det gamle citat af Jamie Zawinski:

Nu du bringer det op, vil jeg da lige henlede din opmærksomhed på dette fremragende stykke digitalarkæologi: http://regex.info/blog/2006-09-15/247

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Thomas Ammitzbøll-bach 2. okt. 2008 - 01.30
 
Der er tre ting at sige om Regex

1) Regex er beregnet til at genkende mønstre og behandle det genkendte som mønstre. Hvis der er vigtige semantiske forhold i mønstrene, bør de behandles separat. Regex er ikke beregnet til at lave tilstandsmaskiner, stak-operationer eller røræg med.

2) Man skal have lige meget fokus på falske positiver som falske negativer. Mange bliver som begejstret for, at de kan matche alle positiver, at de glemmer, at de også matche visse negativer.

3) Regex benytter sig at tilbagesporing, og visse regex-udtryk kan få regex-maskinen til at afsøge en afsindig stor mængde kombinationer. Hvis man skal arbejde effektivt med regex, så skal man kende regex-maskinens afsøgningsalgoritme.

Hvis det er Perl, man bruger, så vil jeg anbefale, at man gør sig bekendt med kamelbogens kapitel om regex. (Eller perlre(3p) man-siden)

Thomas

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Peter Makholms billede
Peter Makholm 2. okt. 2008 - 14.08
 
Den obligate reference

Når nu ikke andre vil, så bliver jeg jo nød til det:

http://store.xkcd.com/#RegularExpressionsShirt

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Carsten Sonne 2. okt. 2008 - 15.10
 
Officiel dokumentation

Til de interesserede kan den officielle dokumentation på tildeling af CPR numre findes her:

http://www.cpr.dk/cpr_artikler/Files/Fil1/4225.pdf

Som allerede nævnt er modulus 11 checket ikke længere gyldigt:

http://www.cpr.dk/cpr/site.aspx?p=132&ArticleTypeID=51&t=ForsideVisartik...

Årsagen er den simple at der kun kan tildeles ca. 540 CPR numre med gyldigt kontrolciffer per dato, hvilket fremgår af dokumentationen.

Til gengæld er det faktisk muligt at se om et personnummer stammer fra 1800, 1900 eller 2000.

Mvh
Carsten Sonne Larsen

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Torben Mogensens billede
Torben Mogensen 2. okt. 2008 - 17.37
 
Re: Der er tre ting at sige om Regex
Regex er ikke beregnet til at lave tilstandsmaskiner, stak-operationer eller røræg med.

Regulære udtryk er netop ækvivalente med tilstandsmaskiner, så det er noget vrøvl.

Men jeg vil give dig ret i, at hvis det regulære udtryk bliver for kompliceret, så skal man flytte noget af verifikationen til bagefter. Og en modulo-11 test er ret oplagt til det. Men det er nu meget sjovt at tænke over, hvordan man vil indbygge det i et regexp eller en DFA. :-)

Jeg har i øvrigt det simpleste (omend ikke det korteste) regexp til genkendelse af lovlige CPR numre:

"0101000000"|...|"3112999999"

hvor "..." dækker over en opremsning af alle andre lovlige CPR numre. :-)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Stig Johansen 2. okt. 2008 - 17.48
 
Hellere overdrive end at være kedelig.

Du René

Sådan har jeg det med det regulære udtryk for personnummer, som jeg lavede for snart 7 år siden.

Det var da sådan set først i 2003 ISB'en gik i luften ikke ?

Og kontrakten løb i 5 år, så det passer meget godt med man skal finde en anden løsning.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Nick G. 3. okt. 2008 - 00.20
 
Bedste = korteste, hurtigst at afvikle eller færrest falske ...

Bedste regex er et vidt begreb.. Det gælder i de fleste tilfælde om at finde en balance mellem hvad der er nøjagtigt, og hvad som er praktisk at bruge. F.eks. er der i RegexBuddy's library en regex der matcher en E-mail adresse som er formateret efter RFC 2822 standarden:

(?:[a-z0-9!#$%&'+/=?^_{|}~-]+(?:\.[a-z0-9!#$%&amp;&#039;*+/=?^_{|}~-]+)|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])")@(?:(?:a-z0-9?.)+a-z0-9?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-][a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])

Men nu er en dato jo noget enklere at beskrive nøjagtigt, så Jeg ville ikke være bekymret for ressourcebruget for nedenstående, den matcher i hvert fald de 11.064 datoer Jeg brugte som test på mindre end et halvt sekund i RegexBuddy, og tager højde for skudår.

For det første bruger Jeg '^' og '$' rundt om hele regex'en, for ikke at matche f.eks. 'ost2806721234hej' ('^' definerer at her starter strengen vi skal matche, og '$' definerer at her slutter den).
For det andet bruger Jeg '(?:)' i stedet for '()' for at øge hastigheden (det betyder at indholdet i paranteserne ikke skal smides ind i en backreference).

Først matcher Jeg '31', og de måneder der kan indeholde 31 dage:

31(?:0[13578]|1[02])

Ellers matcher Jeg '30' eller '29', samt de måneder der kan indeholde op til 30 dage:

(?:30|29)(?:0[13-9]|1[0-2])

Ellers matcher Jeg dage op til 28, og alle måneder:

(?:0[1-9]|1[0-9]|2[0-8])(?:0[1-9]|1[0-2])

Hvis en af de the matchede, tjekker Jeg om der står et årstal [0-9]{2}, ellers tjekker Jeg om det er 29. februar, og et skudår:

2902(?:[02468][048]|[13579][26])

Eftersom det er skudår hvert 4. år (pånær ved århundredeskift som ikke er deleligt med 400, men da CPR numre kun har to cifre for årstal, er det lidt svært at tjekke.. Vi går derfor ud fra at årstallet 00 er år 2000 som er deleligt med 400 og derfor er et skudår), og 4-tabellen gentager sig selv i blokke af 20, er det nemt at regne ud at hvis det andet sidste ciffer i et vilkårligt tal der er deleligt med 4 er lige, så er det sidste ciffer enten 0, 4 eller 8, og hvis det er ulige, så er det sidste ciffer enten 2 eller 6.

Til sidst tjekker Jeg om de sidste 4 cifre er med [0-9]{4}, men der er såvidt Jeg ved ikke nogen regler for dem mere, så der kan vi kun tjekke om de er der.

Jeg har også inkluderet 0000000000 i den samlede regex:

^(?:(?:31(?:0[13578]|1[02])|(?:30|29)(?:0[13-9]|1[0-2])|(?:0[1-9]|1[0-9]|2[0-8])(?:0[1-9]|1[0-2]))[0-9]{2}|2902(?:[02468][048]|[13579][26]))[0-9]{4}|0000000000$

Min regex er således 14 karakterer længere end den på Digitalisér, men tager til gengæld højde for skudår, og er formentlig ikke meget langsommere at afvikle. Så hvad er bedst?

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Martin Glob 3. okt. 2008 - 01.57
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

Dette er jo et glimrende eksempel på, at "udviklere" opfinder løsninger, der løser problemet som de ser det, men som i virkeligheden intet løser...

Der er en måde at validere et personnummer på - og det er at checke om det nu også findes i CPR registret.

Et er at checke formatet, noget andet er at checke om det er validt. Og hvad kan man bruge et CPR-nummer, postnummer eller en vejkode der måske er korrekt til?

Lad dog være med, at forsøge at validerer noget, der ikke kan valideres med en RegExp.

Martin

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Stig Johansen 3. okt. 2008 - 07.43
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...
Der er *en* måde at validere et personnummer på - og det er at checke om det nu også findes i CPR registret.

Enig, jeg forstår ikke disse hypes om 'næsten korrekt' prevalidering.

Disse modulud kontroller (10 + 11) er udviklet i 'offline tiden'.

De har udelukkende til hensigt at fange tastefejl.
Samtidig giver de en vis spredning i nummerserier, så man derved fanger tastefejl.
F.eks. vil kontonummer 1006 og 1009 ikke kunne eksistere i samme system.

(Der er noget der hedder talblind på linie med ordblind, og et helt typisk tegn er, at man f.ekd. bytter om på 6 og 9)

Men hold det på det plan, man undgår aldrig (i et seriøst sytem), at validere op mod stamdata, så for meget preprocessing er spild af tid.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
René Løhde 3. okt. 2008 - 09.42
 
Re: Hellere overdrive end at være kedelig.

Du har ret ISB'en launch var i 2003 og det ser ud som om at dets afløser er digitaliser.dk ...relationen mellem datatypen og hvilket tidspunkt jeg lavede den at, må du fortælle mig ved lejlighed.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
René Løhde 3. okt. 2008 - 10.11
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

@Martin,

Ville det ikke være meningsløst at bede CPR validere "aaaaaaaaaa"? Hvorfor ikke få det Stig kalder en "næsten korrekt prevalidering"?

Husk på denne datatype er udtrykt i regex i Xml Schema - med aaaaalt hvad det indebærer af utilstrækkelighed. Jeg er sikker på at der findes bedre kombinationer til at udtrykke datatyper uafhængigt af programmeringssprog og platform (prøv evt. at søge efter James Clarks 'TEDDY' - tror jeg han kalder det).

...og ja, selvfølgelig vil det formentlig være absolut formålstjeneligt for de fleste systemer at undersøge om CPR nummeret er valid. Men derfor kan vi jo godt få datatypen så rigtig så mulig på et tidligt tidspunkt. Det er vel derfor at der f.eks er javascript input validering i web forms og at Postel formulerede sin "lov".

Denne type og hvordan den udtrykkes er IKKE en "udvikler" løsning. Det er en fælles offentlig beslutning om at lave et typesystem uafhængigt af f.eks leverandør.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
René Løhde 3. okt. 2008 - 10.21
 
Fede kommentarer!

Der er to ting i denne post som jeg håber man reflekterer over

  1. En lille nørdet øvelse med at forbedre et regulært udtryk - tak fordi i leger med jeg bliver så utroligt meget klogere af at læse jeres kommentarer..Peter, Esben, Torben etc tak, og Nick G. whauw...du har lagt noget tid og kvalitet i det svar!

  2. Som Stig har bemærket så er digitaliser.dk helt tydeligvis aftageren for Infostrukturbasen (http://isb.oio.dk/info). I en anden post håber jeg at vi kan få en diskussion af nødvendigheden af et alt-omfang-sig-gribende virtuelt policy dokument lagring, datatype repository og service registry for den offentlige sektor.

-René

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Nick G. 3. okt. 2008 - 11.23
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...
Der er *en* måde at validere et personnummer på - og det er at checke om det nu også findes i CPR registret.

Det er rigtigt, men Jeg tvivler nu altså på at regexen bliver brugt som endegyldigt bevis på at CPR nummeret er ægte, og korrekt..
I min verden, bruges regexes ofte som validering af brugerinput, hvor man ikke lige har adgang til en database over samtlige korrekte kombinationer, som f.eks. i client-side validering i en browser. Selvfølgelig skal den stadig valideres server-side også, og hvis man har adgang til en database over korrekte svar, så er det da oplagt at bruge denne.

Jeg lavede denne regex, under forudsætning af at den skulle bruges et sted, hvor man ikke havde adgang til en liste over korrekte kombinationer. Jeg regnede med at det kunne gennemskues mellem linierne, men det kan da godt være at Jeg skulle have sagt det fra starten..

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Peter Makholms billede
Peter Makholm 3. okt. 2008 - 13.30
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...
F.eks. er der i RegexBuddy's library en regex der matcher en E-mail adresse som er formateret efter RFC 2822 standarden:

Ejj, hvor old-school!

Det er RFC 5322 der er den relevante standard i dag. Kan I så tage at få opdateret jeres kode. (Ok, det er vidst nok kun en kommentar, der skal opdateres)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Martin Glob 3. okt. 2008 - 23.38
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

Selvfølgelig skal man lave en prevalidering - de steder hvor det er relevant.

F.eks. i et skærmbillede hvor man kan lave et "ser det rimeligt ud" check før man forstyrre backenden.

Men...

Er det i en bruger interface vil et simpelt JavaScript give bedre overskuelighed. Og det er langt nemmere at kode en komplet format validering i JS (eller andet sprog) end i en RegExp.

Og det med skemavalideringer har jeg svært ved at se brugbarheden af med mindre den er skudsikker.

Jeg har set alt for mange integrationer mellem systemer gå galt - ikke fordi man ikke kunne forstå at her kom et tal og en streng - men hvad pokker indeholdet af data betød og hvad udfaldsrummet var - og det bliver nemt totalt uoverskueligt med en regexp.

Filosofien er god nok, men så snart man kommer ud over banale data går det galt.

I stedet for følgende:

<pattern value="((((0[1-9]|1[0-9]|2[0-9]|3[0-1])(01|03|05|07|08|10|12))|((0[1-9]|1[0-9]|2[0-9]|30)(04|06|09|11))|((0[1-9]|1[0-9]|2[0-9])(02)))[0-9]{6})|0000000000" />

ville en format forklaring uden for skemaet som f.eks:

ddmmyynnnn|0000000000

være nemmere at forstå. Især hvis der var en henvisning til en uddybende forklaring.

Slås med den slags dagligt ;-)

Martin

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Martin Glob 3. okt. 2008 - 23.42
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

Og ja... så er det lige at jeg burder være lidt mere vågen og se, at det jeg ville foretrække rent faktisk står i <documentation> tagget ;-)

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Maciej Szeliga 4. okt. 2008 - 09.33
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

Det er helt klart færrest falske positiver, den anden mulighed er kun OK i tilfælde af at man skal bruge det til statistik. Specielt når det gælder CPR-nr. er det kritisk og bør slet ikke give falske positiver, dvs. det skal også kunne håndtere personer som er over 100 år.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Nick G. 4. okt. 2008 - 12.20
 
Re: Bedste = korteste, hurtigst at afvikle eller færrest fal ...

En revidering af min regex, der tager højde for at personer der er født i år 1900 ikke kan være født d. 29. februar, kunne se sådan her ud:

^(?:(?:31(?:0[13578]|1[02])|(?:30|29)(?:0[13-9]|1[0-2])|(?:0[1-9]|1[0-9]|2[0-8])(?:0[1-9]|1[0-2]))[0-9]{3}|290200[4-9]|2902(?:(?!00)[02468][048]|[13579][26])[0-3])[0-9]{3}|0000000000$

Som Carsten nævnte, så bestemmer det 7. ciffer i CPR nummeret hvilket århundrede man er født i. Hvis der står 00 i årstal, og det 7. ciffer er 0, 1, 2 eller 3, så er årstallet 1900. Ellers er det 2000, så hvis de første 6 cifre i et CPR nummer er 290200, så skal det 7. være mellem 4 og 9: 290200[4-9]. Hvis det 7. ciffer er mellem 0 og 3, så ignorer 00: 2902(?:(?!00)[02468][048]|[13579][26])[0-3]

Men Jeg vil give de fleste personer i tråden ret, det er nemmere og mere læsbart hvis valideringen foregik i kode. En JavaScript valideringsfunktion kunne se således ud:

[code=javascript]function ValidateCPR(val, args) {
args.IsValid = args.Value == "0000000000";
if (!args.IsValid && args.Value.length == 10) {
var dd = Number(args.Value.substring(0, 2));
var mm = Number(args.Value.substring(2, 4));
var yy = Number(args.Value.substring(4, 6));
var n = Number(args.Value.substring(6, 7));
if (!isNaN(dd) && !isNaN(mm) && !isNaN(yy) && !isNaN(n)) {
if (n >= 0 && n <= 3) {
yy += 1900;
}
else if (n == 4 || n == 9) {
yy += ((yy < 37) ? 2000 : 1900);
}
else if (n >= 5 && n <= 8) {
yy += ((yy < 58) ? 2000 : 1800);
}

        args.IsValid = IsValidDate(dd, mm, yy);  
    }  
}  

}

function IsValidDate(day, month, year) {
var IsLeapYear = year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
var arrDaysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if (month > 0 && month < 13) {
if (arrDaysInMonth[month - 1] >= day && day > 0) {
if (month != 2 || (month == 2 && (IsLeapYear || (!IsLeapYear && day <= 28)))) {
return true;
}
}
}

return false;  

}[/code]

Men om man bruger regexen, eller JavaScriptet, er i dette tilfælde underordnet, de giver det samme resultat.

Uanset hvad, så bad René om en regex, og det har han fået.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Stig Johansen 4. okt. 2008 - 18.35
 
Sikkert ikke aktuelt mere.

Men jeg er rimeligt sikker på, at for en små 30 år siden, betød 5 i 7. ciffer, at årstallet var 18xx, og ikke 19xx
i sagens natur var 20xx ikke defineret.

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Nick G. 4. okt. 2008 - 18.59
 
Re: Sikkert ikke aktuelt mere.

Det gør det stadig. Hvis det 7. ciffer er mellem 5 og 8, og årstallet er 58 eller højere, så er det 18xx. Er årstallet under 58, så er det 20xx.

[code=javascript]else if (n >= 5 && n <= 8) {
yy += ((yy < 58) ? 2000 : 1800);
}[/code]

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Fritz Henglein 4. okt. 2008 - 19.48
 
Re: Ét og kun ét regexp?

Rene skriver:

"Sådan har jeg det med det regulære udtryk for personnummer, som jeg lavede for snart 7 år siden.

Jeg er sikker på at det kan laves bedre og jeg er villig til at udlodde en T-shirt for et det bedste regulære udtryk for personnummer, som bliver posted her i kommentarerne inden for de næste 30 dage."

og henviser til en side med en specifikation af et regulært udtryk i den konkrete syntaks XML Schema bruger for regulære udtryk.

Der er efter min mening følgende 3 problemer ifm. spørgsmålet, hvoraf dog kun det sidste er alvorligt:

o Dokumentation og specification er i konflikt med hinanden: Schema specifikationen tillader strenge såsom 2902071466, men dokumentationen siger, at de første seks cifre skal repræsenterer fødselsdage. Det er måske uheldigt, men ikke problematisk: Rene efterspørger en anden løsning til det regulære udtryk. Den eneste fortolkning man kan lægge i det er: Det givne regulære udtryk denoterer et sprog (en mængde af endelige tegnfølger); venligst find en anden specifikation, som denoterer den samme mængde af tegnfølger. Der efterlyses ikke noget, som udelukker 2902071466 (tværtimod, det skal være med), afgør om 1801022911 eksisterer som nøgle i CPR-registret i går, i dag eller i morgen, eller prøver at gætte sig til, om vedkommende er en gammel mand eller sidder på en skolebænk. Det drejer sig om en mængde af tegnfølger.

o Rene bruger "regulære udtryk" i teksten, men i overskriften står der "Regex" . Desværre synes "Regex" eller også "RexExp" inspirere til det der omtales som 'regulære udtryk' i Perl og og andre matching-annoterede sprog bygget oven på regulære udtryk. Jeg ved for lidt om Perl, men det er nok sikkert at sige, at Perls Regexer er lige så meget regulære udtryk som foreningen af alle sprog talt i EU er det samme som Engelsk. Da Rene henviser til en XML Schema definitions konkrete syntaks for regulære udtryk (som denoterer kun mængder af tegnfølger, ikke noget med matches), vil jeg antage, at han også efterlyser en løsning i samme sprog. Så det er heller ikke problematisk.

o Løsningen skal være "bedre", men bedre i forhold til hvilket kriterium? Måske kortere i antal tegn brugt for at specificere det samme, som en slags sport eller obfuskationsøvelse? (Det synes at være en fortolkning, der er blevet anlagt.) Eller mere effektivt i den forstand, at det fører til en hurtig genkendelsesrutine? (Det er blevet nævnt. Det giver dog næppe mening: strengene er ekstrem korte og selv hvis millioner af dem skulle processeres vil konstruktionen af en DFA, selv for 16-bit processering som vil nok give hurtigst performance på standard-pc'er, være en hurtigt overstået øvelse.) Eller måske "rigtig" i henhold til dokumentationen, altså for at udelukke tegnfølger som 2902071466? (Bemærk, at det kræver lidt afklaring: 2902001466 vil nok skulle tillades--man kan jo alligevel ikke uddrage en entydig fødselsdato af en streng.) Eller mere læselig i den forstand, at den reflekterer den abstrakte syntaktiske struktur af et personnummer (først dag, så måned, år, de 4 cifre)?

Det eneste svar, jeg derfor har er: Rene, hvad præcis er "bedre"?

Ellers kommer vi programmører jo alle med vores egne -- forkellige og gensidigt inkonsistente -- fortolkninger: hvorfor spørge, når man kan afgøre det selv i "koden", selvfølgeligt uden at skrive det i specifikationen eller dokumentationen. Så havner vi jo bare der, hvor livsgrundlaget for den store skare af maintenance programmører bliver skabt: Dagens hurtige beslutning bliver morgendagens opgave -- og så fremdeles...

Men hvem vil være maintenance programmør (for ikke at nævne betale for det...)?

Fritz

PS: Hvis det er sidste fortolkning af "bedre", vil jeg i øvrigt nominere din egen løsning, dog med undtagelse af, at jeg ville splitte de sidste 6 cifre op i 2 grupper, et for årsdelen og et for gruppen af de 4 cifre til sidst. Jeg ville også skrive udtrykket over flere linier, med indentering der reflekterer den abstrakte syntaks og med kommentarer om, hvad de enkelte dele repræsenterer. Bemærk at genkendelses-DFAen bliver lige så hurtigt...

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
Carsten Sonne 4. okt. 2008 - 23.56
 
Re: Sikkert ikke aktuelt mere.

Algoritmen bygger på:
http://www.cpr.dk/cpr_artikler/Files/Fil1/4225.pdf

Se tabellen på side 5-7.

Den syntes korrekt :)

Mvh
Carsten Sonne Larsen

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
René Løhde 3. nov. 2008 - 10.18
 
Kontakt i First World

Peter Makholm, Esben Damgaard, Nick G. og Fritz Henglein!

Hvis I sender mig jeres postadresse, samt jeres t-shirt størrelse, så sender jeg en t-shirt i jeres retning.

renel@microsoft.com

Tak for deltagelsen!

-René

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer
René Løhde 4. nov. 2008 - 12.15
 
Re: Ét og kun ét regexp?

Hej Fritz,

Jeg skylder dig et svar og det har trukket ud, dels fordi jeg ikke kan svare. Du har ret - bedre i forhold til hvad?

Jeg har reflekteret og det jeg nok var ude efter var en slags "Kim Larsen" for det regulære udtryk. Dvs et folkeligt, "laveste fællesnævner" regulære udtryk, som opfører sig homogent på heterogene platforme - gerne med hensyn til perfekt syntax, så komplet semantisk kontrol så muligt, en afvejning af kompakthed vs. programmør læsevenlighed og computation for udtrykket - (effektiv CPU behandling).

-René

  • Stem op 0
  • Stem ned 0
  • Log ind eller opret en konto for at skrive kommentarer

Tilføj kommentar

Opret en konto eller log ind for at følge indhold på Version2 - og bliv opdateret via e-mail eller rss

Følg kommentarer
Log ind herunder eller opret en bruger for at skrive kommentarer
Du kan logge ind med din e-mail-adresse
Der er forskel på store og små bogstaver i adgangskoden.
Glemt adgangskode?

Seneste nyt

Ny blog stiller skarpt på juraen i it-kontrakter

Udgivet 10. feb 10.00Opdateret 10. feb 10.00

Windows 8 Consumer Preview klar til download 29. februar

Udgivet 10. feb 9.49Opdateret 10. feb 9.49

4 gode sikkerhedsråd: Sådan gør du firma-pc'en vinterferieklar

Udgivet 10. feb 8.01Opdateret 10. feb 8.01

Konklusion af Polsag-review fra 2009: Elendig kode hånd i hånd med elendig kontrakt

Udgivet 10. feb 6.59Opdateret 10. feb 9.21

It skal spare kommunerne for 165 millioner kroner i 2012

Udgivet 9. feb 16.02Opdateret 9. feb 16.02
Flere it-nyheder »
Få it-nyheder og blogs hver dag med Version2's nyhedsbrev.

Seneste debat

  1. Derfor bliver dårlige it-projekter ikke stoppet i tide

    2 comments.
    Last update 34 sekunder
    Skrevet af Peter Johan Bruun
  2. Microsoft frigiver Android-version af OneNote

    1 comment.
    Last update 5 minutter 20 sekunder
    Skrevet af Mads Randstoft
  3. Ny agil trend: Fordel opgaverne med positiv psykologi

    1 comment.
    Last update 8 minutter 47 sekunder
    Skrevet af Mads Randstoft
  4. Så oldnordisk er politiets it-miljø: Nostalgisk gensyn med 1980’erne

    12 comments.
    Last update 19 minutter 21 sekunder
    Skrevet af Steen Guttknecht
  5. Konklusion af Polsag-review fra 2009: Elendig kode hånd i hånd med elendig kontrakt

    7 comments.
    Last update 38 minutter 37 sekunder
    Skrevet af Adam Tulinius
  6. 4 gode sikkerhedsråd: Sådan gør du firma-pc'en vinterferieklar

    3 comments.
    Last update 43 minutter 58 sekunder
    Skrevet af Maciej Szeliga
  7. Stop SOPA, PIPA, ACTA, TPP og alle dem der kommer efter

    51 comments.
    Last update 58 minutter 32 sekunder
    Skrevet af Jesper Lund Stocholm
  8. Apple vildleder danske kunder med dårlig serviceordning

    16 comments.
    Last update 1 time 29 minutter
    Skrevet af Jesper Poulsen
Mere debat »

Information

  • Kontakt redaktionen
  • Job- og annoncesalg
  • Teknisk support
  • Om Version2
  • Brugerbetingelser
  • Privatlivspolitik

Aktuelle emner

  • Agil udvikling
  • Android
  • Bruttolønsordning
  • Business Intelligence
  • Cloud computing
  • Digitaliseringsstyrelsen
  • HTML5
  • Harddisk-priser
  • IE9
  • Intranet
  • It-sikkerhed
  • Kindle Fire
  • Multimedieskat
  • NemID
  • OS X Lion
  • Open source CMS
  • Projektledelse
  • Scrum
  • Sharepoint intranet
  • Storage
  • Ubuntu 11.10
  • Virtualisering
  • Windows 8
  • Windows Phone 7
  • iOS 5
  • iPhone 4S

Tjenester

  • Android-app
  • iPhone-app
  • RSS-feeds
Følg @version2dk
Få it-nyheder og blogs hver dag med Version2's nyhedsbrev.

Version2 udgives af

  • Mediehuset Ingeniøren A/S work Skelbækgade 4 1717 København V
  • Tlf. work 33265300