Avatar billede msdb Nybegynder
14. december 2010 - 15:00 Der er 14 kommentarer og
1 løsning

Python, gem linie nr ved indeksering

Jeg er igang med at lave en søgemaskine som bla. skal kunne indeksere nogle tekster. Programmet er næsten færdig, jeg vil dog gerne tilføje linienumre til søgeoutputtet, dvs. når der søges på et ord skal output ikke blot være de relevante tekster og antal af reultater, men også hvilke linienumre disse fremkommer på.
Jeg indekserer teksterne med denne funktion:

import re
stop = open('stopord.txt').read()
re_split = re.compile('[ .,;:!?*)(/\n\r\t-]+')
stopord = re_split.split(stop)

def nuke(text):
    f = open(text).read()
    words = list(re_split.split(f))
    t = [w.lower() for w in words if w != ',' and w != ':' and w != '(' and w != ')' and w != '-' and w.isdigit() == False]
    b = [w for w in t if w not in stopord]
    return b

Jeg tænker at løsningen ligger i at lave om på re_split og muligvis tilføje en løkke, som tildeler indekstermerne en værdi, ved hvert linieskift og smider resultatet ind i en dictionary.

Er dette den optimale løsning, hvis overhovedet mulig?
Avatar billede arne_v Ekspert
15. december 2010 - 03:29 #1
Logikken skal nok ændres en hel del.

Hvis du læser en linie ad gangen, inkrementerer en tæller for hver linie og gemmer en struktur af tæller plus ord i en liste, så burde du have det.
Avatar billede msdb Nybegynder
15. december 2010 - 04:02 #2
Den logik kan jeg sagtens følge, men udover tælleren kan jeg ikke greje en metode til at gemme tæller og ord. Jeg misforstår måske din mening. Kan du uddybe?
Avatar billede arne_v Ekspert
15. december 2010 - 04:12 #3
Til inspiration:

lst = []
lst.append( { 'line':1, 'word':'A' } )
lst.append( { 'line':2, 'word':'BB' } )
lst.append( { 'line':3, 'word':'CCC' } )
for itm in lst:
    print itm['word'],'er i linie',itm['line']
Avatar billede msdb Nybegynder
15. december 2010 - 13:51 #4
Dette returnerer en liste af linienumre:

#t1 er teksten
lst = []
bla = []
lines = 0
l = 'line'
w = 'words'
for line in t1.splitlines():
    lines += 1
    lst.append({l:lines, w:line})
for itm in lst:
    if 'agurk' in itm['words']:
        bla.append(itm['line'])
        print itm['line']
print bla


... men koden kan ikke findet ordet, hvis det f.eks. starter med stort bogstav, hmm, hvad mangler jeg?
Avatar billede arne_v Ekspert
16. december 2010 - 02:34 #5
Jeg forstår ikke helt hvilke keys du bruger. Bruger du l og w eller words og line??
Avatar billede msdb Nybegynder
16. december 2010 - 03:01 #6
Hvad mener du? Vi kan hurtigt blive enige om at det er en forvirrende opskrift jeg hat bikset sammen, men den virker.
Hvis jeg f.eks. printer lst, så returnerer den næsten det som du foreslog, dvs. en dictionaey med linjenummer sammen med ordene i den linje. Det ser således ud for en tekst på 3 linjer:
[{'line': 1, 'words': 'Agurk'}, {'line': 2, 'words': 'Cucumis Sativus/Anguria'}, {'line': 3, 'words': 'Gherkin, small cucumber'}]
Avatar billede arne_v Ekspert
16. december 2010 - 03:07 #7
Ah - jeg missede at du brugte varible som keys. Så passer det jo fint sammen.

D.v.s. at dit problem er kun at lave en case insensitiv sammenligning?
Avatar billede arne_v Ekspert
16. december 2010 - 03:09 #8
Jeg tror at du bliver nødt til splitte linien i ord og så sammenligne case insensitivt ved at kalde .lower() på begge.
Avatar billede msdb Nybegynder
16. december 2010 - 03:35 #9
Nu har jeg forsøgt med den regex-funktion som du hjalp mig med i en tidl. tråd, nemlig
re_split = re.compile('[ .,;:!?*)(/\n\r\t-]+')
for-løkke nr. 2 smider hvert ord enkeltvis ind under linjenr. men når jeg indsætter h i anden løkke får jeg en fejl. Hvordan kan det være?

for line in t1.splitlines():
    lines += 1
    g = re_split.split(line)
    h = [x.lower for x in g]
    for wd in g:
        lst.append({l:lines, w:wd})
Avatar billede msdb Nybegynder
16. december 2010 - 03:49 #10
Never mind, jeg glemte ()
Avatar billede arne_v Ekspert
16. december 2010 - 03:51 #11
Ved nærmere eftertanke behøver du ikke engang splitte i ord.

if 'agurk' in itm['words']:

->

if 'agurk'.lower() in itm['words'].lower():
Avatar billede msdb Nybegynder
16. december 2010 - 03:54 #12
Output ser nu sådan ud:
[{'line': 1, 'words': 'agurk'}, {'line': 2, 'words': 'cucumis'}, {'line': 2, 'words': 'sativus'}, {'line': 2, 'words': 'anguria'}, {'line': 3, 'words': 'gherkin'}].. osv
Nu er den i stand til at finde 'agurk' i første linje, men ikke hvis det f.eks. staves 'agurken' eller lign. variation. Burde den ikke kunne finde ud af det når jeg spørger:
if 'agurk' in itm['words']:
?
Avatar billede arne_v Ekspert
16. december 2010 - 03:58 #13
print 'agurk' in 'agurk'
print 'agurk' in 'agurken'
print 'agurk' in 'Agurk'
print 'agurk' in 'Agurken'
print 'agurk' in 'Agurk'.lower()
print 'agurk' in 'Agurken'.lower()

virker helt som forventet her:

True
True
False
False
True
True
Avatar billede msdb Nybegynder
16. december 2010 - 04:07 #14
AHHhhh, det er mig der ikke tænker. 'Agurk' forekommer 14 gange i teksten og 13 af dem står i samme linje, det tænkte jeg ikke lige over da jeg bedømte mit output. Jeg har nu testet et andet ord og kan konkludere at det virker perfekt.
Endnu engang tak for din hjælp :)
Avatar billede arne_v Ekspert
16. december 2010 - 04:13 #15
så smider jeg et svar
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