BLOG  Sproglige Former

M8 - enkle løsninger
Skip Navigation LinksM8 > Sproglige former

En blog fra M8 og RetKomma

Nested Regular Expressions explained

This article was originally written for The Code Project and can be found at the location http://www.codeproject.com/useritems/Nested_RegEx_explained.asp. Therefore it is written in (a more or less well formed) English.

Introduction

A cool feature of the .NET RegEx-engine is the ability to match nested constructions, for example nested parenthesis. I will describe this feature somewhat in depth in this article. If you are an experienced RegEx developer, please feel free to go forward to the part: The push-down automata.

Background

Regular expressions are a very cool feature for pattern recognition in strings. Mathematically speaking regular expressions are parsed through a finite state machine. As the name implies such a machine has only a finite number of states, and it has no external memory attached. This means, that the finite state machine cannot match nested constructions such as: “(9 + (5 + 3))”. Or a more specific task:

Tell me if and where the string str has a number of correct nested parenthesis.

Though, if the finite state machine is supplied with an external stack, the mathematics state, that this would be possible - and that’s what has happened in the .NET RegEx engine. Through smart use of external stacks it is now possible to match nested constructions. So let’s see how it gets the job done.

The beginning: Captures

(Feel free to skip this part if you already have a solid knowledge of regular expressions).

In a regular expression you can always use parenthesis to capture a specific part of the recognized pattern. A quick example:

Source text
mymail@mycompany.com

Regular expression
([^@]+)@([^.]+)\.(\w{2,4})

This is a (too) simple expression which attempts to capture a mail address. Let’s run through the parenthesis:

1. ( [^@]+ )

The first parenthesis matches any number of characters which is not a @-symbol. The expression is encapsulated in a parenthesis, and therefore the RegEx engine will capture this part of the source into a group numbered 1. This group can be accessed at runtime like this:

 

String pattern = @"([^@]+)@([^.]+)\.(\w{2,4})"; 

String source = "mymail@mycompany.com"; 

Match match = Regex.Match(pattern, source); 

match.Groups[1].Value; // returns "mymail" 

match.Groups[1].Index; // returns 0; 

2. ( [^.]+ )

Likewise, after the @ in the email address the above expression will capture any text until it reaches a period. This will be captured in to group number 2.

3. ( \w{2,4} )

Finally this will capture the rest of the expression - the top level domain - into group number 3.

The fundamentals: Named captures

Even though this is not a new feature, named captures are fundamental for understanding the nested constructions in .NET regular expressions.

In the previous chapter parenthesis were used to capture a part of the source into a group. The groups were named with successive integers beginning with 1 (by convention Groups[0] captures the whole match).

But it is also possible to capture parts of the source into named groups, with the following simple syntax:

(?<user>[^@]+) @ (?<company>[^.]+) \. (?<top_level_domain>\w{2,4})

In the code the groups can now be accessed like this:

 

String pattern = @"([^@]+)@([^.]+)\.(\w{2,4})"; 

String source = "mymail@mycompany.com"; 

Match match = Regex.Match(pattern, source); 

// returns "mymail": 

match.Groups["user"].Value; 

// returns "mycompany": 

match.Groups["company"].Value 

// returns "com": 

match.Groups["top_level_domain"].Value 

This is not a new part of a regular expression engine - you would find the same to exist with almost the same syntax in languages like Python and PHP.

But the .NET regular expression engine uses the principle of named capturing to provide features for the developer to create a regular expression which is capable of matching nested constructions. Now, let’s check that out!

The push-down automata

As stated in the beginning of this article a finite state machine is not capable of matching nested constructions. This is actually the reason that Chomsky in the 1960’s argued that a finite state machine cannot recognize a natural language such as English.

A push-down automata is a finite state machine with an external memory - a stack - attached. This framework provides a basis for understanding how the .NET RegEx engine is capable of matching nested constructions. Let’s see some code.

Now, let’s say that the task is to match nested <div>’s in HTML code.

 

String pattern = @" 

(?# line 01) <div> 

(?# line 02) (?> 

(?# line 03) <div> (?<DEPTH>) 

(?# line 04) | 

(?# line 05) </div> (?<-DEPTH>) 

(?# line 06) | 

(?# line 07) .? 

(?# line 08) )* 

(?# line 09) (?(DEPTH)(?!)) 

(?# line 10) </div> 

";source = "<div>asdf<div>asdf</div>asdffds</div>"; 

Match match = Regex.Match(source, pattern, 

  RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase); 

Console.WriteLine(match.Success.ToString()); 

First (line 1) this expression matches an opening div. This is mirrored by an ending closing tag </div> in line 10.

In line 2 the first group begins. It is an unnamed atomic group. Atomic means roughly that once something is matched, the RegEx-engine won’t give it up again. This might sound a bit strange at first, but it can be important to performance. To keep focus in this article I won’t elaborate further on it. But notice that this parenthesis is ended in line 8 with a * meaning: repeat as many times as possible.

Now the important stuff begins. Line 3 to 7 is an alternation with three possibilities. Either it should match a <div> or a </div> or a single character .?. When alternation occurs, the .NET RegEx engine will tryout the matches one at a time accepting the first match - even if this is not the longest match. (This is as far as I know opposed to a deterministic finite automaton).

When the RegEx engine matches a <div> (line 3), it is at the same time told to match something else: (?<DEPTH>). Remember the stuff about named capturing? This actually is a capture with the name DEPTH. It is empty, though! So while the group doesn’t actually capture anything from the source, it does something else, which is very important - it creates a new stack, let’s pretend it’s called DEPTH, and it puts the capture on that stack!

This means that we now have a new stack called DEPTH with one element on it containing an empty string. This is quite interesting - so let’s dig a bit deeper into it.

Check this out:

 

( 

(?<A>a) 

| 

(?<B>b) 

)*

Here we’ve also used named capturing, but we don’t just capture an empty string, we are capturing the letter a onto the stack A and the letter b onto the stack B. As seen before we can request this using the code: match.Groups["A"].Value;.

Now, let’s change the code a bit:

 

( 

(?<A>a) 

| 

(?<A>b) 

)*

Now both groups are named A. What happens this time? If we take this source: ab, the RegEx engine will first match the a. By doing this it creates a new stack called A and it pushes the a on the stack. Next it matches the b. It already has created a stack named A, so it just pushes a new element on the stack with the capture b. So now our stack looks like this:

 

Stack 'A' 

________ 

|      | 

|   b  | 

|   a  | 

|______| 

If you uses the same code to request what’s captured in group A (match.Groups["A"].Value) you would get the string “b” - the Groups object simply peeks the top element on the stack.

This stack invention is quite cool - but what’s even cooler is, that is let’s you pop elements off the stack inside the regex pattern, which is what happens in this example:

( 

(?<A>a) 

| 

(?<A>b) (?<-A>) 

)*

Again, consider the input string ab. First the RegEx engine matches the a, creates a new stack and pushes an a on it. Next, the engine matches a b and pushes it on the stack. Now the syntax changes: (?<-A>). This empty capturing parenthesis actually pops the top element off the A stack. To ensure this actually happens try the code once again: match.Groups["A"].Value. Now this code returns the string “a” even though the last character matched was “b”. The reason is, that the b was popped off the stack immediately after it was pushed on. So the stack contains only one element, i.e. the a.

Okay - back to the DIV’s in our main example.

Whenever the RegEx engine matches a <div> it pushes an empty string on the stack. On the other hand: whenever it matches a </div> it pops the stack. Doing this - the stack would end up empty if and only if the RegEx engine discovers a correct nested construction of DIV’s.

This is what the final expression is testing (line 9):

(?(DEPTH)(?!))

This is actually a conditonal test. A conditional test is of the well known form if-then-else in the syntax:

(? (if) then | else)

The if-part tests if the named group was matched and stored. If it was matched the then-part of the expression is applied, else the else-part is applied. Note that the else-part is optional.

What the last expression (?(DEPTH) (?!)) does then, is that it tests if the named group DEPTH was captured and stored. If it was, the then-part is applied (?!) forcing a negative lookahead with no expression, which will always fail. Hence, the whole expression fails if the number of (?<DEPTH>) doesn’t match the number of (?<-DEPTH>) applied in a correct nested order. You can test this last part your-self with an expression like this:

Given the source aba this expression will not succeed. First it matches the a and pushes it on the stack, then the b (without pushing) and pops the stack - now the stack is empty. Then it checks to see if the stack has been matched and stored - it hasn’t, so it will try to match a b where the source has an a. On the other hand, the source abb will succeed with a match.

Points of Interest

The invention of an auxiliary stack in the .NET RegEx engine has made it possible to match nested constructions and keep track of the matches bringing even more power to regular expressions. And it let’s you push, pop and to some extend peek the stack from within the RegEx engine.

Also, it is possible to create multiple stacks with different names keeping track of more complex expressions.

Morten Maate

Skriv en kommentar

‘At’ er sprogets cooleste ord

In the bottom of my heart har jeg aldrig været i tvivl om, at der er ét ord på dansk, der overgår de andre.

Ordet at er ubetinget det cooleste ord i ordbogen. Her er hvorfor:

  • at er både et ord og en ordklasse
  • at er aldrig tvetydigt (ingen homonymi)
  • at indleder altid enten en ledsætning eller en infinitivkonstruktion
  • at er et af de få danske ord, der ikke har noget semantisk indhold
  • at er en ‘ren’ bisætningsindleder - ikke noget hokuspokus med også at ‘kunne indeholde’ et subjekt som fx der og som kan

Både et ord og en ordklasse

Der er ingen andre ord i dansk, der har samme distributionsmønster som ordet at. Ordet at kan således forekomme på helt unikke måder, hvilket berettiger til at give det sin egen ordklasse. Det havde det rent faktisk også i den første udgave af RetKomma!

Ingen homonymi

Ordet at kan kun være en indordningskonjunktion. Intet andet. Okay, indrømmet - de fleste ord kan gøres til substantiv eller verbal i obskure sætningskonstruktioner. Fx skriver den store danske poet Højholt i digtsamlingen Turbo perverterede ting som: “her er er er er her er er er”, og jeg hørte engang en konsulent bruge verbet ‘at messestande’, og at har sikkert været udsat for lignende kreativ sprogbrug. Men i udgangspunktet og langt de fleste tilfælde: at har intet med homonymi at gøre.

Ledindleder

Ikke nok med at at ikke er udsat for homonymi, det har også altid den samme egenskab i sætningen, nemlig at indlede et sætningsled - nærmere bestemt et komplekst sætningsled - nærmere bestemt enten en ledsætning eller en infinitivkonstruktion - eller at fungere som konjunktion i en akkussativ med infinitiv.

Ingen semantik

Ordet at har intet semantisk indhold. Ordet udgøres af ét morfem, nemlig at, og det er et grammatisk morfem. At fortæller sprogbrugeren: Sats dit liv på, at det efterfølgende er et nominalled.

Intet hokuspokus

Ordet at kan kun være en normal konjunktion, - ikke noget med en skizofren konjunktion som der og som, der også kan indeholde et subjekt.

Kort sagt: at er en gave til alle, der beskæftiger sig med at automatisere sprog!

Skriv en kommentar

Ordklassernes betydning for analysen af sætningsled

Det går hastigt fremad med den første betaudgave af RetKomma. Vi har oprindeligt planlagt at frigive den i næste måned, og måske når vi det… Et af de fænomener, vi har arbejdet meget med, er, hvor meget syntaktisk viden, man kan tvinge ud af enkeltord.

Det er - desværre - ikke så normalt at tale om, at bestemte ord eller ordklasser har en grammatisk funktion.

Indirekte er de fleste grammatikere dog alligevel inde på det, når de beskriver de enkelte sætningsled. Eksempelvis er det i reglen en del af beskrivelsen af et nominalled, at det afsluttes med en substantiv
- eventuelt efterfult af et adled:

  • jeg så et hus
  • jeg så et hus med et flot tag

I sætningerne ovenfor kan nominalledets hus fx ikke efterfølges af et nyt substantiv. Man kan ikke sige jeg så et hus bil. Det eneste, der kan efterfølge ordet hus, er således et adled: med et flot tag. Adledet er igen bygget op som en præposition + en nominalhelhed, hvor ordet tag ikke kan efterfølges af endnu et substantiv.

Det er en ekstremt nyttig viden, når man skal lære en computer, hvad et nominalled er. For det indebærer, at vi kan opstille en regel, der siger, at et substantiv altid afslutter en nominalhelhed. På den måde bidrager de enkelte ordklasser til den grammatiske analyse. Men ingen grammatik uden undtagelser:

  • jeg spiser et stykke rugbrød
  • jeg spiser en masse legoklodser

I disse sætninger indeholder hvert nominalled 2 substantiver: stykke og rugbrød samt masse og legoklodser.

Det er således muligt at identificere en række lignende substantiver, som kan efterfølges af et substantiv. Det drejer sig om:

  • et stykke
  • en mængde
  • en række
  • en liter
  • et kilo
  • en meter
  • substantiver der ender på ‘-gram’
  • substantiver der ender på ‘-liter’
  • substantiver der ender på ‘-meter’
  • en masse
  • en del
  • en anelse
  • alle substantiver der ender på ‘-fuld’, fx en håndfuld
  • eller som ender på ‘-fulde’

Finder du flere, må du meget gerne poste dem her på bloggen.

Et andet meget vigtigt ord, der tidligere er omtalt her på bloggen, er ordet ikke. Det gælder for alle centraladverbialer, dvs. adverbialer, der kun kan forekomme på sætningsskemaets a-plads (i.e. umiddelbart før et eventuelt infinit verbal i en hovedsætning eller umiddelbart før et finit verbal i en bisætning), at de jf. deres definition ikke kan stå sidst i hverken en hoved- eller bisætning, hvor ’sidst’ er defineret som A-pladsen. Derfor er centraladverbialer som ikke fx med til at afgrænse ledsætninger:

  • i går spiste ham du kender ikke lego

En computer ville i udgangspunktet regne ikke for en del af ledsætningen, hvis ikke den havde den syntaktiske viden om, at centraladverbialer ikke kan stå på ledsætningens A-plads. Suppleret med denne viden er den således i stand til at analysere ledsætningen korrekt - et eksempel på, at en bestemt ordklasse bidrager til den syntaktiske analyse af et sætningsled, det ikke selv er en del af.

Som vi tidligere har været inde på, kan netop dette fænomen i øvrigt være med til at forklare, hvorfor ledsætninger har omvendt ordstilling, og faktisk er centraladverbialerne på flere punkter så vigtig en del af RetKomma’s grammatik, at analysen af dem er næsten lige så kompleks som analysen af almindelige adverbial- og nominalhelheder.

En sidste, meget interessant ting, som er helt nyt i RetKomma, er placeringen af adverbialer i nominalhelheder:

  • jeg er endnu højere
  • jeg er højere endnu

I første sætning er endnu en del af nominalleddet endnu højere. I næste sætning, derimod, er endnu et selvstændigt sætningsled, nemlig et adverbial. Det ses bl.a. ved, at endnu i anden sætning selvstændigt kan flyttes rundt i sætningen: endnu er jeg højere.

Måske kan dette fænomen bidrage til forklaringen af, hvorfor adverbialled altid følger efter nominalled?

Som sagt er det en helt spæd tanke, men det forekommer mig at være interessant. I hovedsætninger følger adverbialer altid efter nominaler, jf. sætningsskemaet: F | v n a | V N A.

Og hvis vi ser på bisætningsstrukturen, ændrer det sig ikke: k | n a v | V N A.

I dansk afgøres de enkelte ords ’tilhørsforhold’ af topologien og ikke af morfologien. Det vil sige, at vi analyserer ord som værende en del af et sætningsled pba. ordets placering i forhold til andre ord, og ikke på baggrund af ordets bøjning, sådan som man gør i fx latin.

På denne baggrund kan vi formulere reglen: Hvis et adverbium forekommer før et substantiv eller adjektiv, er adverbiet en del af et nominalled, hvis adverbiet forekommer umiddelbart efter et substantiv eller et adjektiv, er adverbiet et selvstændigt sætningsled (adverbial).

Herudfra kan vi måske drage en mere generel betragtning om sætningsstrukturen. Muligvis er denne regel en del af forklaringen på, hvorfor danske sætninger ser ud, som de gør. Med andre ord: Placeringen af adverbialer efter nominaler gør det entydigt, hvornår et adverbium fungerer som adverbial i sætningen, og hvornår adverbier er en del af et nominalled. Hvis den omvendte struktur eksisterede, ville sætningen jeg er endnu højere med andre ord være tvetydig.

Her skal man dog være opmærksom på, at ikke alle adverbier kan fungere som en del af et nominal, især kan centraladverbialer aldrig være en del af et nominal.

Skriv en kommentar

Æ, ø og å på hjemmesider

På baggrund af søgeresultaterne her på bloggen kan jeg se, at mange efterspørger, hvordan man koder specialtegn som æ, ø og å i html på en hjemmeside. Lad mig for de interesserede googlere derfor kort resumere.

Html-encoding af æ, ø og å

Html-standarderne har deres egen kode, som garanterer, at et bogstav altid bliver vist korrekt. For de danske æ, ø og å er det:

Bogstav   Html-kodning   Decimalværdi*
æ & aelig; & #230;
ø & slash; & #248;
å & aring; & #229;
Æ & AElig; & #198;
Ø & Oslash; & #216;
Å & Aring; & #197;

denne side kan du finde en oversigt over html-koderne for andre special-tegn såsom α og β.

*Unicode

I Unicode-standarden har hvert bogstav en kode, som er angivet som en firecifret hex-værdi med foranstillet ‘u+’, fx u+0000.

I Html-kodningen er det muligt at adressere et tegn fra Unicode-standarden, hvis man omregner tegnet til decimaltal. Fx har bogstavet Æ koden u+00C6. Omregnet til decimaltal er det: 6 * 1 + C * 16 = 198 (hvor C = 12). I tabellen ovenfor fremgår det, at dette er den såkaldte decimalværdi for tegnet Æ, som kan skrives som Æ.

Charset

Den sidste mulighed er at undersøge, hvordan dit html-dokument er kodet. Ofte vil det være UTF-8-kodning, men er siden skrevet i bl.a. Windows Notepad, er det ofte en anden type encoding, som vil variere fra computer til computer. Når du ved, hvilken encoding, der er valgt, kan du tilføje et Content-Type-tag, som ofte vil angive UTF-8 eller iso-8859-1:

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>

eller

<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″>

Tag’et tilføjes som det første i head-sektionen. Når brugerens browser møder dette tag, genindlæser den dokumentet forfra med den angivede encoding. Læs også dette blogindlæg om unicode-encoding.

Ved xhtml-dokumenter kan du i stedet tilføje dette tag som den første linje i dokumentet:

 <?xml version=”1.0″ encoding=”utf-8″?>

 Hvis din encoding er sat korrekt, kan du skrive specialtegn direkte i din editor, der så vil lagre tegnene som de rigtige hex.

Skriv en kommentar

Software kan ikke lære sprog - uden hjælp…

Jeg læste en artikel i går, hvor en forsker havde lavet en ‘computerbaby’.

Idéen var at implementere nogle basale regler i et computerprogram, regler, som man kan forvente et menneske er født med, give programmet en uendelig tekstmængde og se, hvad det lærer.

Jeg har selv beskæftiget mig med noget, der lugter af det samme. Dels teoretisk i artiklen her, og dels i arbejdet med RetKomma. Derfor var min første tanke: Jeg ved, at det kan ikke lade sig gøre!

Det blev jeg ved med at tænke, indtil jeg nåede ned til slutningen af artiklen, hvor journalisten gjorde opmærksom på, at computerbabyen anvendte skriftsprog og ikke talesprog. Og det er en afgørende forskel. Det har den ulempe, at det ikke simmulerer børns sprogindlæring, fordi børn jo ikke lærer sprog gennem skrift, men gennem tale. Omvendt ville det nok også være sådan, jeg selv ville gribe det an, for det siger trods alt en del om principperne for sprogtilegnelse alligevel. Man kan sige, at hvis mennesket ikke var udstyrret med egenskaben til at frembringe lyde så kontrolleret, så havde vi måske udviklet et skriftssprog i stedet for et talesprog - sprog er sprog.

Men jeg tror, det kan lade sig gøre med skriftsprog

Som det måske fremgår, tror jeg, at man kan nå ret langt i at få en computer til at opstille en grammatik automatisk, blot den får skrift nok at arbejde med.

Det interessante i denne sammenhæng er, hvorfor det ikke kan lade sig gøre med talesprog.

For at starte fra brunden består tale af lyd. Hvis vi lytter til et sprog i radioen, vi ikke forstår noget af, er det således umuligt at identificere et eneste betydningsadskillende element.

Lad os for eksemplets skyld antage, at en japaner hører dansk i radioen. Hun vil ikke kunne sige, hvor der starter et ord, eller hvor et ord slutter, men hvad der er lige så interessant: Hun ville ikke kunne identificere bogstaverne - uanset om hun hørte dansk radio fra hun blev født til hun døde, ville hun ikke lære et ord dansk, og hun ville ikke engang kunne opstille noget der minder om et alfabet. Forudsat, naturligvis, at hun ikke lærer eller hører dansk på en anden måde end fra denne radio:)

Det er helt bogstaveligt ment: ikke et ord. Heller ikke en ordform - hun ville altså ikke kunne sige. Det her er et dansk ord - de siger det i radioen hele tiden, men jeg ved godt nok ikke hvad det betyder.

- I teorien i hvert fald. Måske ville hun lære enkelte ord, hvis de blev gentaget hele tiden og aldrig indgik i en sætning. Fx i en jingle, hvor der bare bliver sagt P3 eller The voice. Men ingen ord i en sætning.

Hvad ved jeg egentlig om det?

For at starte fra bunden, er ord opbygget af lyde, men det er ikke alle lyde, der er betydningsadskillende. Lad os tage ordene haj og kaj. Her er lydene h og k betydningsadskillende, for hvis vi tager ordet haj og udskifter h‘et med k, så ændrer ordet betydning.

Men hvad med ordene han og hav? Her er lydene n og v forskellige og lydene a og α er også forskellige, hvor det første a er lys, og det andet α er mørkt. Men kun n og v er betydningsadskillende. Hvis vi udtaler han med et mørkt α, ændrer det ikke betydning, og tilsvarende hvis vi udtaler hav med lyst a.

Med andre ord er der et arbitrært forhold mellem lydene og betydningen - vi har vedtaget, at nogle lyde ændrer betydning, hvis vi skifter dem ud med hinanden, og at andre ikke gør. På den måde grupperer vi de ‘nøgne’ lyde i egentlige fonemer. Fonemet /a/ indeholder således både det lyse a og det mørke α, fordi en indbyrdes udskiftning af disse to lyde ikke gør noget ved betydningen af et ord. Det er disse fonemer, vi har ‘oversat’ til bogstaver i vores skriftssprog. Det vidner også om, at talesproget har udviklet sig en del - der er efterhånden kommet stor afstand mellem bogstaverne i skriften og fonemerne i udtalen. Forskellen på dansk tale- og skriftssprog er som jeg ser det ikke meget mindre end på dansk og norsk, og som sådan kan man godt kalde det to forskellige sprog.

Men det er en anden diskussion. Det relevante her er det, der gør en lyd til et fonem: nemlig betydningen. Hvis ikke vi ved, hvad ord i en tekst betyder, kan vi ikke foretage den mest grundlæggende af alle analyser. Vi kan ikke fremstille et bogstav, fordi alle lyde så at sige kan være lige gode - fonemet /a/ kunne lige så godt bestå af lydene a og i. Den eneste grund til, at vi kan afgøre, at det ikke er tilfældet, er, fordi a og i er betydningsadskillene (fx hil og hal), men det kræver, at vi ved noget om betydningen. Derfor vil japaneren, der lytter til danske sætninger aldrig kunne identificere et eneste ord, fordi hun ikke kan identificere et fonem. Hun vil med andre ord høre forskel på lyse og mørke a’er, og på de i øvrit udendeligt mange forskellige måder at udtale et ord på - for hun ved ikke, hvad hun skal lytte efter - hvad det er for et lille bestemt træk ved udtalen af en lyd, der gør den til en del af netop det ene fonem frem for det andet.

Og det er derfor, at en computer ikke kan opstille en grammatik, selvom det hører uendeligt meget tale. Den kan simpelthen ikke gruppere talen på nogen fornuftig måde. I et sprogindlæringsperspektiv er det også interessant, at børn - og nu bevæger jeg mig ud i et område, jeg egentlig ikke ved noget om - begynder at pege på ting. Peger og siger hund. For før man kan begynde at sammensætte sætninger og forstå ord, er det nødvendigt at høre de samme ord gentaget og identificeret med én bestemt betydning igen og igen for at få de helt grundlæggende byggeklodser - fonemerne - på plads.

Hvis en computer derfor skal gøre det samme trick, er den nødt til at have enten noget skriftsprog at arbejde med - i skriftsproget fonemanalysen jo lavet på forhånd - eller computeren skal have sproget forarbejdet på en anden måde, fx begynde med at modtage 10.000 forskellige måder at sige hund på og tilsvarende for ord som mund, lund, hun - osv. Eller den skal forlænges med en robot, der kan agere barn, som efterligner mennesker, peger og siger hund.

Jeg har forgæves forsøgt at finde en reference til den artikel, der indledte denne blog.

Skriv en kommentar

Københavns Kommunes hjemmeside er en charterrejse. Kforums er en backpacker-oplevelse.

Hvordan kan de store offentlige og private hjemmesider se til fra sidelinjen, mens Web 2.0 eksploderer for øjnene af dem? En del af det skyldes forskellige brugergrupper, men der er stadig rum til forbedring.

Tidens webkultur med brugergenereret indhold er mildest talt eksploderet; Kforum er et godt eksempel. Her samler sitet brugernes artikler, powerpoints, blogs, profiler osv. Sitet leverer således både information, netværk og et nyt job.

På Kforum er strukturen flad og netværksorienteret, og der er ikke en forside, der dikterer, hvordan brugerne færdes på sitet. Det er en væsentlig ting, Kforum har til fælles med andre nye sites.

Forskellen bliver tydelig, hvis man ser på hjemmesiden for Københavns Kommune. Her er der ingen tvivl om, at forsiden er en indgang for brugeren, og at sitet er opbygget efter helt andre hierarkiske principper.

Enten må der derfor være en afgørende forskel i formålet med sites som Kforum.dk og kk.dk, der gør det nødvendigt med så forskellige arkitekturer. Eller også er Kforum.dk en first mover på nettet, der sammen med en gruppe lignende sites baner vejen for de større offentlige og private sites.
En forskel mellem information og services
Der er en væsentlig forskel på de to sites formål, som kan være med til at forklare strukturerne. Her tænker jeg særligt på den serviceorienterede arkitektur (SOA).

En service kan typisk erstatte et besøg på kommunen eller en telefonopringning til en kundemedarbejder. Services på nettet sparer virksomheden for en betydelig mængde sagsbehandling, og det er enklere og mere fleksibelt for borgeren fx at kunne ændre folkeregisteradresse online.

En overordnet forskel mellem Københavns Kommune og Kforum er derfor:

  • at Københavns Kommune som andre store offentlige og private sites skal levere services eller sikre et salg
  • mens Kforum, som hører til de brugergenererede sites, primært formidler viden og netværk.

Den serviceorienterede fejlslutning
Men betyder det, at større offentlige og private sites kun skal levere services og ingen information? Åbentlyst nej. Københavns Kommune har fx et behov for at fortælle om politiske tiltag i kommunen - det kunne være om overborgmesterens projekt billige boliger.

Men mange af de større offentlige sites er bygget op omkring services i en grad, så det går ud over informationsformidlingen. Det har i flere år været et mantra, at forsiden skal være øverst i et hierarki, hvor borgeren vælger mellem flere forskellige indgange til virksomheden.

Tanken om indgange til forskellige veje, brugeren kan følge, tilgodesér imidlertid primært én type bruger, nemlig den bruger, der besøger sitet for at anvende en service - og det er næppe den største brugergruppe. Hun ankommer typisk via forsiden, og hun ved præcis, hvad hun søger. Som en charterturist, bliver hun rutinemæssigt guidet til sit mål, og hun kommer for at få en bestemt service.

Informationssøgerens søgeadfærd står derimod i kontrast til hjemmesidernes hierarkiske struktur. Når brugeren søger information foregår det ikke ved at spørge: Hvor skal jeg hen for at finde informationen?

Det drejer sig med andre ord ikke om leverandøren af informationen, men slet og ret om informationen. Det foregår derfor via Google, og informationsleverandøren bliver det site, der ligger højt på en Google-søgning, og som rent faktisk leverer informationen, når brugeren klikker sig ind - og det er vigtigt: Informations-leverancen skal foregå med det samme, ellers er brugeren væk igen. Hun spilder sjældent tid på at sætte sig ind i hjemmesidens indre logik og besøger stort set aldrig forsiden.

Men når brugeren finder informationen, er hun til gengæld oftere gavmild. I artiklens feriemetafor kan hun sammenlignes med backpackeren, der strejfer rundt efter en oplevelse, og som gerne involverer sig i rejsemålet - i form af et svar på en blog eller en profil på fx Kforum.

To eksempler på mere tilgængelig information
Fra virksomhedens synspunkt er det vigtigt at levere sin vinkel på informationen. Det kan især være vigtigt i et politisk system. Samtidig er det en betydelig sidegevinst, hvis brugeren opdager en service eller et produkt, hun ikke er klar over, at virksomheden udbyder.

Derfor er det vigtigt at præsentere brugeren for umiddelbare alternativer til den aktuelle side, så brugeren bliver på sitet i stedet for straks at klikke væk igen, selvom informationen ikke leveres på side 1.

Her kan det være nødvendigt at bryde med den hierarkiske tankegang. Dynamiske links og emneordsnavigation er to elementer, virksomhederne passende kan ‘låne’ fra web 2.0-kulturen.

Dynamiske links
Dynamiske links er én måde at præsentere brugeren for en række direkte, nærliggende alternativer til den side, hun først kommer ind på.

Siden genererer automatisk 1-3 links på baggrund af den aktuelle sides søgeord og information om brugeren: Hvor i landet sidder hun? Hvilke søgeord har hun anvendt for at komme ind på siden? Hvilke søgeord har hun søgt på inde på siden? Hvad har hun tidligere været interesseret i?

På den måde oprettes der links til de alternative sider, der er størst sandsynlighed for, at brugeren er interesseret i. Det er således et skridt tættere på målet: Det øger chancen for, at virksomheden leverer informationen, og at brugeren bliver opmærksom på andre af virksomhedens services eller produkter.

Emneords-navigation
Samtidig vil flere virksomheder givetvis finde det anvendeligt i højere grad at anvende emneords-navigation. Ved emneordsnavigation har brugeren mulighed for at se en oversigt over alle sider på det aktuelle site, som indeholder samme emneord som den viste artikel - uden om den hierarkiske struktur.

Emneordsnavigation anvendes allerede i forskellig udstrækning på web 2.0-sites, og det er et must på enhver blog. Emneordsnavigation kan eventuelt udvides med mere visuelle elementer som fx en tag pool, der opsummerer nogle af de mest viste emneord, eventuelt tilpasset viden om den aktuelle bruger.

Information er også en service
Det er ikke usandsynligt, at et af de næste vigtige skridt på nettet bliver, at større offentlige og private virksomheder kombinerer deres hierarkiske SOA-struktur med mere seriøse interne søgefunktioner, dynamiske links, emneords-navigation og tag pools, der kan guide informationssøgerne på vej til den rette information og holde dem på sitet, - og på den måde skabe genveje på tværs af et ellers traditionelt og mere rigidt hierarkisk site.

Information er også en service. Det er vigtigt af både politiske og strategiske grunde at blive brugerens informationsleverandør, ligesom en mere sikker informationsleverance i sidste ende kan spare virksomheden for en irriteret bruger og tid på mailen eller i telefonen.

Med andre ord: Tving aldrig en backpacker med på charterrejse! Men lad også være med at hive tante Olga gennem nepalesiske landsbyer. Virksomhederne skal ikke bryde med gode SOA-principper og hierarki. De store stites har ikke behov for en revolution, men web 2.0-principperne kan hjælpe hurtigt ind - hurtig ud-brugerne til at skyde genvej på tværs af hierarkiet til de destinationer, hvor informationen er.

Skriv en kommentar

Semantisk søgning

Diskussionerne om semantisk søgning er gået  hårdt for sig det seneste stykke tid med nye påfund som Hakia og Powerset.

Søgemaskinen Hakia er blandt de nye tiltag, som særligt markedsfører sig på semantisk søgning. Ambitionen er at finde de mest relevante websites baseret på søgesætningernes betydning. Her ligger der implicit en kritik af rent statistisk funderede søgemaskiner (også kaldt vektorbaserede søgemaskiner), for hvem siger, at det de sider, der bliver vist oftest, altid repræsenterer det bedste søgematch?

Og det er en vigtig del af debatten. Vektorbaserede søgemaskiner fokuserer (i hvert fald de senere år) meget på, hvor mange andre sider der linker til den enkelte side, hvilket giver et mål for sidens popularitet. Herudover anvender de i høj grad mere matematisk eller statistisk funderede regler, som fx optæller antallet af ordforekomster i et dokument og sammenligner det med antallet af ordforekomster i andre dokumenter sammenholdt med data for fx hvor tæt ordene står sammen.

I dette blogindlæg skriver Hakias direktør lidt om filosofien bag den semantisk orienterede søgemaskine. Til eksempel giver han sætningen what is Palladium useful for? Han hævder, at Hakia vil genkende sætningskonstruktionen og regne ud, at det drejer sig om metallet palladium, mens en statistik baseret søgemaskine som Google måske vil returnere sider om London-teatret Palladium. Det er selvfølgelig oplagt at prøve selv:

Ja, den store forskel er der vel ikke, når det kommer til stykket… Nu skal man jo heller ikke være blind for, at selvom Hakia markedsfører sig på at være en semantisk søgemaskine i opposition til Google, så er en stor del af de grundlæggende tanker antageligt de samme, og ligesom Google antageligt ikke ligger på den lade side i forhold til at optimere deres søgeresultater med semantik og andre lingvistiske midler, så undlader Hakia nok heller ikke at skæve til gode, gammeldags vektorbaserede søgemetoder.

Powerset

Powerset er endnu ikke offentliggjort, men har alligevel fået meget omtale på nettet. Tim Converse skriver her lidt om nogle traditionelle søgemetoder og skitserer nogle af visionerne for Powerset. En grundlæggende pointe er, at søgemaskinerne skal gå fra at beskæftige sig med sprogets form, til at beskæftige sig med de såkaldte dybdestrukturer - det vil groft sagt sige sprogets semantik og/eller syntaks. Dette ud fra en divise om, at sprogformen ikke altid alene siger noget om, hvordan enkeltord relaterer sig til hinanden. - Som en kommentar på bloggen meget fornuftigt lyder:

“I certainly do not agree with saying that we have squeezed as much as we can out of vector models, although possibly out of pure linear spaces.

I definately agree with the idea of doing further linguistic work to the text first, though, and I thoroughly enjoyed this article. I think the emphasis has to go on combining something along the lines of neural networks with the existing vector models, where many people I have heard talking about this recently have suggested completely removing the vector approach - which seems to be throwing away years of work”

Skriv en kommentar

Automatiske søgeord på hjemmesider

Som en afstikker i forbindelse med udviklingen af RetKomma-projektet er vi netop blevet færdige med en fuldautomatisk nøgleordsgenerator, som bl.a. kan anvendes til automatisk at finde søgeord på en hjemmeside. 

Hvorfor er det vigtigt med søgeord på hjemmesider?

Nogle meget gode grunde er, at søgeord kan siges at fungere som pejlemærker for søgemaskiner som Google - hjemmesiden bliver med andre ord lettere fundet af brugerne. Søgeord kan også danne fundament for mere avancerede teknologier såsom dynamiske links, hvor en hjemmeside selv opretter links fra én side til andre nærliggende sider (som der eksempelvis argumenteres for muligheden af i dette paper).

Kort sagt kan søgeord således være med til at skabe fundamentet for den endelige nedbrydning af en traditionel ‘pyramideopbygget’ hjemmeside.

Nøgleordsgeneratoren kan testes i en demo-udgave på vores hjemmeside. Prøv det, og giv gerne en kommentar:) Demo-udgaven er gratis.

Det banebrydende ved generatoren er, at den er fuldautomatisk, og at det er lykkedes os at udarbejde en algoritme, der kan fortælle, hvilke ord der er de vigtigste i et dokument. Så vidt vi ved, er der ikke andre på markedet, det er lykkedes for, og derfor er det jo i sig selv interessant.

Andre nøgleordsgeneratorer

I forbindelse med udarbejdelsen af nøgleordsgeneratoren har vi tjekket en række forskellige generatorer, som enten ikke er fuldautomatiske, eller som alternativt ikke er funderet på en dynamisk algoritme, men snarere er afhængig af diverse tommelfingerregler - og det fungerer bare ikke nær så godt.

Vi vil derfor tillade os at mene, at nøgleordsgeneratoren faktisk er det første seriøse bud på en nøgleordsgenerator, (1) fordi den kan implementeres, så den fungere automatisk hver gang en hjemmeside ændres, (2) fordi den automatisk finder de vigtigste ord på en hjemmeside ud fra en matematisk algoritme, som er uafhængig af tommelfingerregler, men derimod vurderer hvert enkelt ord for sig, (3) fordi den er funderet på en åben standard (WSDL-webservice) og derfor kan implementeres på stort set enhver software-platform.

Andre bud på nøgleordsgeneratorer er:

Her vil vi fremhæve PHP Classes og Topicalizer som nogle af de bedre generatorer. 

Nøgleordsgeneratoren er et af de sprogteknologiske produkter, som er udsprunget af RetKomma-projektet sammen med diverse artikler og en sprogvidenskabelig viden, hvor en del bliver kommenteret på denne blog.

Nøgleordsgeneratoren fungerer i øjeblikket kun til dansksprogede hjemmesider.

Skriv en kommentar

NLP i praksis

Jeg faldt over dette blogindlæg i dag http://technigal.wordpress.com/2007/07/16/natural-language-processing-the-indian-perspective/, som handler om nogle af de konkrete problemstillinger, Indien har ved at være et land, der består af mange forskellige grupper med hvert deres sprog.

Som artiklen er inde på har en af løsningerne på problemet allerede set dagens lys: Unicode. For helt at fange fidusen med Unicode, er det vigtigt at huske på, at en computer ikke kan forstå tekst, kun tal - ja, kun 1-taller og 0′er. Når en tekststreng derfor skal gemmes, skal den kodes som en række tal, og hvad der er lige så vigtigt: når den skal hentes frem igen, skal modtageren være enig med afsenderen om, hvordan teksten er kodet - ellers opstår situationer som denne:

Encoding - Der er opstået en fejl, prøv igen senere

Her har afstenderen glemt at informere modtageren om, hvordan teksten er kodet. De fleste tegn kan modtageren ‘gætte’ sig frem til, men over for specialtegnene æ, ø og å giver modtageren op - de kan være kodet som hvad som helst, og for computeren er der ikke større sandsynlighed for, at det er et æ, end at det er et tilfældigt japansk tegn.

Lidt historie for at forstå nutiden

Førhen blev tekst kodet med 7 bit - det vil sige en række af syv 1-taller og 0′er. Fx svarede tegnet A til 65, som omskrevet til det binære talsystem svarede til 100001.

Dette tegnsystem kaldes ASCII og har den meget store begrænsning, at det kun kan indeholde 128 forskellige tegn (svarende til 128 forskellige måder at kombinere 7 på hinanden følgende 1-taller og 0′er). Dog har det samtidig den store fordel, at dets tegn svarer til dem, der anvendes i engelsk/amerikansk. I en globaliseret verden er 128 forskellige tegn dog langt fra tilstrækkeligt.

Der blev på et tidspunkt skabt præcedens for at gruppere bits i bytes således at 8 bit svarede til én byte. Samtidig gik det binære talsystem af mode, og man indførte i stedet et hexadecimalsystem. I vores normale titalssystem (decimalsystemet) har vi tal fra 0-9, men i et hexadecimalsystem anvender man tal fra 0-15. Derfor noteres hexadecimalsystemet med tal fra 0-9 samt bogstaverne A-F for hhv. tallene 10-15. Hexadecimalsystemet er egentlig bare en praktisk måde at forkorte det binære talsystem på. Eftersom bits altid grupperes i bytes, der består af 8 bit, kan en byte blive repræsenteret med 2 hexadecimaltal, hvor hvert ciffer svarer til fire bits - også kaldet en nibble. I stedet for at skrive bogstavet A som 1000001 kan det således i stedet forkortes til 41, hvor 4-tallet repræsenterer nibblen: 0100, og 1-tallet repræsenterer 0001.

Men hov - i den binære ASCII-kodning svarede A til 1000001, mens det samme skrevet med hexadecimalsystemet svarer til 41, som igen svarer til 01000001. Det er det samme tal, men med et 0 foran. Det betyder, at man ved at gruppere bits i bytes for hver byte havde en bit, man ikke brugte til noget - denne bit vil altid være 0, så længe tekst kodes med ASCII-kodning. IBM fandt derfor på at udvide ASCII-kodningen til at kunne rumme 256 forskellige tegn, så man dermed gjorde brug af den ekstra bit. Dette system blev meget udbredt, og der opstod en situation, hvor alle var enige om de første 128 tegn, men de sidste 128 tegn, verden med ét havde fået i overskud, blev anvendt vidt forskelligt fra sprogområde til sprogområde. I Danmark var det naturligt bl.a. at anvende tegnene til æ, ø og å, men sendte man et elektronisk dokument til USA, ville de talkoder, der med en dansk udvidelse af tegnsættet betød æ, ø og å, betyde noget helt andet.

Unicode: Før Babelstårnet vælter

Systemet med 128 faste tegn + 128 nationalt bestemte tegn holdt i mange år, men især internettet og den stigende overførsel af digitaliseret tekst har gjort det særdeles uholdbart med kun 256 forskellige tegn - især fordi halvdelen af disse tegn betyder noget forskelligt fra land til land.

I eksemplet ovenfor har BaneDanmarks hjemmeside givet en fejlmeddelelse, hvor browseren har erstattet æ, ø og å med spørgsmålstegn. Når browseren kunne gætte sig frem til de øvrige, almindelige vestlige tegn, er det således historisk betinget. Det er, fordi man altid har været enig om de første 128 tegn, som bl.a. består af tal samt bogstaverne fra a-z og A-Z. De øvrige tegn har man tilgengæld altid været uenige om kodningen af.

Unicode er løsningen på dette sprogvirvar. Unicode er en relativt kompleks standard, og derfor vil jeg kun beskrive den overfladisk (og delvist fejlagtigt). Finden med Unicode er basalt set at udvide kodningen af tegn fra 1 til 2 bytes. Mens ASCII-tegnsættet og dets efterfølger kunne skrives med 1 byte, så skrives Unicode-tegn groft sagt med 2 tegn. I stedet for 41 for A ville man skrive 0041. Husk, at overgangen fra 128 til 256 tegn blev skabt, fordi man havde 1 bit i overskud. Hver gang man kan finde en bit mere at kode et tegn med, bliver der med andre ord åbnet op for dobbelt så mange tegn. 7 bit giver således 2 opløftet i 7 = 128 muligheder, mens 8 bit giver 2 opløftet i 8 = 256 muligheder. Med en hel byte mere har man pludselig (igen groft sagt) 2 opløftet i 16 = 65.536 forskellige tegn. Men det er ikke hele historien. Unicode-standarden er som sagt kompleks, og den kan kodes på flere forskellige måder. Et af unicodeformaterne anvender faktisk 4 bytes svarende til 2 opløftet i 32 = ca. 4 milliarder forskellige tegnkombinationer. Unicode-standarden indeholder således et tegnsæt, der rummer alle tegn i hele verden samt tegnsæt for nogle ikke-eksisterende sprog såsom fantasisproget Klingon.

Blandt andet derfor er Unicode så helt igennem fantastisk. En anden superfin feature ved Unicode er, at det kan kodes relativt med 1 bytes. Det vil sige, at de tegn, der ikke behøver at fylde mere end 1 bytes, kun fylder 1 byte, mens mere komplekse tegn kan fylde op til 4 bytes. Disse forskellige kodninger benævnes UTF eller Unicode Transformation Format, og den netop nævnte relative kodning med 1 byte benæves UTF-8, fordi der går 8 bit på en byte. UTF-8 er ved at blive den mest anvendte kodning af hjemmesider.

Men der er jo altid et men

Unicode er en abstraktion. Okay, hvad i alverden betyder det? Man kan tænke på det med en metafor hentet fra Platon - Unicode-tegnet A er ikke et fysisk A, men en idé om et A. Hvis et stykke software ved, at det skal forstå en bestemt tegnkode som A, fx 0100 0001, så forstår det idéen A, men det ved principielt ikke noget om, hvordan A’et skal skrives, hvordan det ser ud med fed skrift osv. Det er her skrifttyper eller fonte kommer ind i billedet. En font er en konkret repræsentation af et tegn fra et tegnsæt - men hvis ikke du har en font på computeren, som kender et tegn, så hjælper det ikke, at softwaren godt ved, hvad det er for et tegn - det vil groft sagt aldrig være i stand til at fortælle brugeren det. Det må så enten vælge et andet tegn, typisk en firkantet boks eller et spørgsmålstegn, eller det må udelade tegnet.

Hvor kom vi egentlig fra?

Okay, alt det her tekniske snak er et forsøg på at konkretisere, hvilke sprogteknologiske problemer der forekommer i lande, hvor man taler mange forskellige sprog og er afhængig af at kunne udveksle dokumenter digitalt. Det er jo meget godt med et stærkt redskab som Unicode, der kan rumme alle tegn på én gang, men det hjælper jo ikke på alle de historiske dokumenter, der i forvejen er kodet med tidligere tiders tegnsæt. Her er modtageren af dokumenterne afhængige af både at have installeret de korrekte tegnsæt på sin computer og af at have nogle skrifttyper, der kan visualisere tegnene. Og for at det ikke skal være løgn, så kan nogle tegnsæt ikke eksisterer side om side på en pc (eller det kunne de ikke førhen i de glade DOS og Windows 3.x-dage - måske man har fået redskaber til det nu?), så i enkelte tilfælde skal man have én pc til nogle sprog, en anden til andre sprog. Bottom line: Tak Unicode!

Skriv en kommentar

Hvorfor har ledsætninger omvendt ordstilling?

Gennem arbejdet med RetKomma stødte jeg pludselig på en meget god grund til, at ledsætninger ikke har samme struktur som helsætninger.

Det er formodentlig læseren bekendt, at ledsætninger har såkaldt omvendt ordstilling. Fx hedder det i en helsætning: Du elsker da at spise lego, mens det i en ledsætning hedder: fordi du da elsker at spise lego. Bemærk placeringen af ordet da. I helsætningen kommer ordet da efter verbet elsker. I ledsætningen kommer ordet da før ordet elsker. Det er groft sagt den primære strukturelle forskel på en helsætning og en ledsætning. Hvordan dette ser ud i en normal syntaktisk fremstilling har jeg været nærmere inde på i dette blogindlæg.

Idéen opstod gennem arbejdet med RetKomma, der jo i sagens natur ikke har samme intuitive forståelse for, hvad en ledsætning er, som vi sprogbrugere har. Lad os se på en eksempelsætning:

i dag spiser ham du kender ikke lego

I denne sætning er vi sprogbrugere ikke i tvivl om, at ledsætningen er:

i dag spiser ham [(som) du kender] ikke lego

Jeg har indsat et som, for at gøre det mere tydeligt, hvor ledsætningen begynder. Det vil sige, at ordet ikke er en del af helsætningen og ikke en del af ledsætningen.

Men hvordan ville det forholde sig, hvis ikke ledsætninger havde omvendt ordstilling? Jo, så ville ovenstående sætning være tvetydig, for så ville ikke enten kunne være en del af helsætningen eller være en del af ledsætningen! Sætningen ville med andre ord kunne analyseres således:

* i dag spiser ham [du kender ikke] lego

- Med betydningen: i dag spiser ham, du ikke kender, lego. Hvilket naturligvis er forkert, fordi ledsætninger netop har omvendt ordstilling. Asterisken angiver, at sætningen er ugrammatisk.

Jeg har ikke fundet denne tese beskrevet andre steder, så jeg skrev en lidt længere artikel om fænomenet. Her kommer jeg blandt andet ind på nogle undtagelser, og jeg anvender tesen til at beskrive fænomenet ekstraposition og det fænomen, at nogle ledsætninger ikke har omvendt ordstilling. Samtidig kradser jeg i overfladen på den historiske udvikling af ledsætningsstrukturen fra runeindskrifterne og frem til i dag og argumenterer for, at den omvendte ledsætningsstruktur har været en blandt mange forudsætninger for bortfald af kasus og etablering af en fast helsætningsstruktur. Artiklen ligger her.

Skriv en kommentar

Læs om...



Du finder hele bloggen på WordPress.

Her skriver vi løbende om grammatik, sprogteknologi, tekstprocessering og informationsstrukturer

   Søg   Kontakt    Udskriv