Mit første Python-projekt: hvordan jeg konverterede en uorganiseret tekstfil til en pæn CSV-fil

Så jeg besluttede at lære Python. Det viser sig, at dette computerprogrammeringssprog ikke er så svært (ja, indtil jeg fik dette projekt!: P).

Inden for få sekunder blev jeg forelsket i den nemme, skarpe syntaks og dens automatiske indrykning under skrivning. Jeg blev fascineret, da jeg lærte, at datastrukturer som lister, tupler og ordbog kunne oprettes og initialiseres dynamisk med en enkelt linje (som sådan, list-name = []).

Desuden kunne værdierne i disse tilgås med og uden brug af indekser. Dette gør koden meget læselig, da indekset erstattes af et engelsk ord efter eget valg.

Nå, sagt nok om sproget. Lad mig vise dig, hvad projektet krævede.

Min bror gav mig dette projekt. Han stødte på en tekstfil, der indeholdt tusindvis af ord. Mange af ordene delte næsten den samme betydning. Hvert ord havde sin definition og et eksempel på en sætning ved siden af ​​det, men på en ikke så organiseret måde. Der var mellemrum og nye linjer mellem et ord og dets sætning. Nogle aspekter manglede i ordene. Nedenfor er uddragene af tekstfilen, som jeg taler om:

Han ønskede, at tekstaspekterne skulle være ensartede. Til det havde han brug for, at jeg pænt sorterede alle lignende betydningsord ud for et emne. Han fortalte mig, at dette kunne opnås ved at samle alle data i teksten i en ordbog i følgende format:

og derefter skrive dem ind i en CSV-fil (kommaseparerede værdier).

Han spurgte, om jeg kunne tage dette op som mit første projekt, nu hvor jeg havde lært det grundlæggende. Jeg var begejstret for at udarbejde logikken, og så blev jeg straks enig. Da han blev spurgt om deadline, gav han mig en anstændig tid på 2 dage til at afslutte.

Ak, jeg endte med at tage dobbelt tid, før jeg kæmpede for at fejle den skrevne kode ordentligt. Helt ærligt, hvis det ikke havde været for min brors korte besøg på mit værelse at se på fremskridtene og antyde de forkerte antagelser fra mig, mens jeg skrev betingelserne, var jeg bestemt til at afslutte projektet i evigheden: P

Jeg startede med at oprette mini-opgaver inden for programmet, som jeg forsøgte at afslutte, inden jeg opbyggede hele programmet. Disse var som anført nedenfor:

1. Danner en Regex for at matche et tal og ordet ud for det.

Jeg undersøgte tekstfilen og bemærkede, at hvert emne (heri kaldet 'nøgle') havde et nummer, der gik forud for det. Så jeg skrev et par linier kode for at lave en regex (regulært udtryk - et kraftfuldt værktøj til at udtrække tekst) af mønsteret som følger:

Men da jeg kørte dette, fik jeg en fejl, UnicodeDecodeError, for at være præcis, hvilket betød, at jeg ikke havde adgang til tekstfilen. Jeg slog det op i //stackoverflow.com og efter en lang søgning uden held kom min bror og fandt en løsning. Fejlen blev rettet som følger:

Alligevel fik jeg ikke den ønskede output. Dette var fordi nogle nøgler havde skråstreg ('/') eller mellemrum ('') i teksten, som min regex ikke kunne matche. Jeg tænkte på at forbedre regex-udtrykket senere og skrev derfor en kommentar ved siden af ​​det.

2. Indhentning af en liste over linjer som strenge fra tekstfilen

Til dette skrev jeg kun 1 kode kode og heldigvis dukkede der ingen fejl op.

Jeg fik dog en uren liste. Den indeholdt nye linjer ('\ n') og mellemrum (''). Jeg forsøgte derefter at forfine listen som følger:

3. Uddrag ord, betydninger og eksempelsætninger hver for sig og tilføje dem til tilsvarende lister.

Dette var langt det sværeste at gøre, da det involverede korrekt logik og korrekt vurdering ved mønstergenkendelse.

Interessant nok bemærkede jeg flere mønstre, mens jeg kiggede over tekstfilen. Hvert ord havde sin betydning i samme linje adskilt af et '=' tegn. Hvert eksempel blev også indledt med ':' tegn og 'Eksempel' nøgleord.

Jeg tænkte på at bruge regex igen. Jeg fandt en alternativ og mere elegant løsning ved at skære linjen (nu en streng på listen) i henhold til placeringen af ​​symbolerne. Udskæring er en anden sej funktion i python. Jeg skrev koden som følger:

Ovenstående kode læser næsten som engelsk. For hver linje på den rene liste kontrollerer den, om den har et '=' eller et ':' tegn. Hvis det gør det, findes tegnets indeks, og udskæring foretages i overensstemmelse hermed.

I det første 'hvis' gemmes delen før '=' i variablen 'ord' og delen efter den er gemt i 'betydning'. Tilsvarende for det andet 'hvis' ('elif - ellers hvis - i dette tilfælde), gemmes delen efter': 'i' eksempel '. Og efter hver iteration gemmes ordet, betydningen og eksempelsætningen i de tilsvarende lister. På denne måde kan hele dataene udvindes.

Så langt så godt. Men jeg bemærkede, at udtrækningen skulle udføres på en sådan måde, at hvert ord (og dets aspekter) af den bestemte nøgle skulle akkumuleres sammen som en værdi for nøglen. Dette betød, at det var nødvendigt at gemme hvert ord, betydning og eksempel inde i en tuple. Hver tuple skulle opbevares på en enkelt liste, som ville repræsentere sig selv som værdien for en bestemt nøgle. Dette er vist nedenfor:

Til dette planlagde jeg at samle hvert ord, betydning og sætning for hver nøgle i en separat liste, der er lukket af en anden liste, siger nøgleliste. Igen vil billedet fortælle dig mere præcist:

For at gøre dette tilføjede jeg følgende kode til den, som jeg skrev til udskæring:

Denne kodes logik (den anden del) viste sig desværre at være forkert. Jeg antog fejlagtigt, at der kun var to betingelser ('=' og ':') i teksten. Der var mange undtagelser, som jeg ikke bemærkede. Jeg endte med at spilde timer på fejlretning af mulige fejl i logikken. Jeg havde antaget, at den komplette tekstfil fulgte det samme mønster. Men det var simpelthen ikke tilfældet.

Da jeg ikke kunne komme videre, gik jeg videre til næste del af programmet. Jeg troede, jeg kunne bruge lidt hjælp fra min bror efter at have gennemført de andre dele. : P

Fortsættes…

4. Oprettelse af værdier for taster ved hjælp af Zip-funktion og parameterudpakning.

På dette tidspunkt var jeg ikke helt sikker på, hvad jeg ville gøre, selv efter at have opnået ovenstående konfiguration af lister. Jeg havde lært om 'Zip'-funktion og' Parameter Unpacking 'under en af ​​min brors tekniske samtaler, som bogstaveligt talt zipede de lister, der blev sendt til den, sådan:

Så jeg troede, at jeg på en eller anden måde kunne kombinere disse to funktioner for at opnå det ønskede resultat. Efter en smule to-ing og froing, testede funktionerne og arbejdede på dummy lister, lykkedes det mig. Jeg oprettede en separat fil (beta) til denne opgave, hvis uddrag er angivet nedenfor:

Arbejdet med ovenstående kode kan regnes ud ved at se på output:

Funktionen zip () lynlåser de tilsvarende lister eller værdier i listerne og omslutter dem i en tuple. Tuplerne inde i listerne konverteres derefter til lister til udpakning og yderligere lynlås. Endelig opnås det ønskede output.

Jeg følte mig meget lettet over koden, der fungerede denne gang. Jeg var glad for, at jeg kunne manipulere de potentielt udpakkede data og forme dem i det krævede format. Jeg kopierede koden til hovedfilen, som jeg arbejdede på, og ændrede variabelnavnene i overensstemmelse hermed. Nu var der kun tilbage at tildele værdier til tasterne i ordbogen (og selvfølgelig udvindingsdelen!).

5. Tildeling af værdier til tasterne i ordbogen.

Til dette kom jeg til denne løsning efter nogle eksperimenter med koden:

Dette producerede det ønskede output som følger:

Programmet var næsten færdigt. Hovedproblemet lå i dataudvindingsdelen.

... fortsættelse fra afsnit 3

Efter timer og timers debugging blev jeg mere og mere frustreret over, hvorfor den forbandede ting ikke fungerede. Jeg ringede til min bror, og han gav mig et subtilt tip om de antagelser, jeg havde gjort, mens jeg definerede de betingede sløjfer og if-else-klausuler. Vi gennemgik tekstfilen og bemærkede, at nogle ord havde eksempler i to linjer i stedet for en.

I henhold til min kodelogik, da der ikke er noget ':' tegn i anden linje (eller et '=' tegn, for den sags skyld), ville indholdet i linjen ikke blive behandlet som en del af eksemplet. Som et resultat ville denne erklæring gøre den sidste 'ellers' del sand og udføre koden skrevet i den. I betragtning af alt dette ændrede jeg koden som nedenfor:

Her er hasNumbers () en funktion, der kontrollerer, om en given linje har tal i sig. Jeg definerede det som følger:

Hvad dette gør er, at det samler den anden linje i eksemplet, hvis alle andre betingelser mislykkes, kombinerer den med den første linje og derefter tilføjer den den tilsvarende liste som før.

Til min skuffelse fungerede dette ikke og viste i stedet en fejl om, at indekset var uden for rækkevidde. Jeg var dum, da hver linje kode syntes at være logisk korrekt efter min mening.

Efter timevis af vanvid viste min bror mig en måde at hente de linjenumre, hvor fejlen opstod. En af de vigtigste færdigheder i programmering er evnen til at fejle programmet, korrekt kontrollere for mulige fejl og opretholde en kontinuerlig strøm.

Interessant nok rapporterede følgende tilføjelse til koden, at fejlen opstod omkring linjenummer 1750 i tekstfilen.

Dette betød, at programmet fungerede godt indtil dette linjenummer, og at min kode var korrekt! Problemerne lå i mine forkerte antagelser og også i tekstfilen takket være dens heterogenitet.

Denne gang bemærkede jeg, at nogle nøgler ikke var efter deres tal, hvilket forårsagede problemer i den logiske strøm. Jeg har rettet fejlene ved yderligere at ændre koden som følger:

Dette fungerede godt indtil linje 4428 i tekstfilen, men styrtede lige efter. Jeg kontrollerede linjenummeret i selve tekstfilen, men det hjalp ikke meget. Så indså jeg meget til min lykke, at det måtte være den sidste linje. Hele programmet arbejdede på den rene liste, der var ugyldig med nye linjer og mellemrum. Jeg udskrev den sidste linje på den rene liste og sammenlignede den med den sidste linje i tekstfilen. De matchede!

Jeg var meget glad for at vide dette, da det betød, at programmet blev udført indtil slutningen. Den eneste grund til, at det styrtede ned, var at ingen af ​​koden efter den sidste sætning gav mening. Mine betingede er designet til hver gang også at kontrollere den næste linje sammen med den aktuelle linje. Da der ikke var nogen linje efter sidste linje, styrtede den ned.

Så jeg skrev en ekstra linje kode for at dække det:

Alt fungerede nu. Endelig! Nu skulle jeg bare tildele tasterne til tilsvarende værdier, og det er det! Jeg tog en pause i dette øjeblik i betragtning af at mit projekt endelig var overstået. Jeg vil tilføje nogle sidste detaljer til det senere.

Men inden jeg tog en pause, besluttede jeg at vedlægge hver kode i forskellige funktioner for at få koden til at se pæn ud. Jeg havde allerede meget problemer med at navigere op og ned ad kodelinjerne. Så jeg besluttede at tage en pause efter at have gjort dette.

Men efter at have gjort det, begyndte programmet at give variabelt omfangsfejl. Jeg indså, at dette var fordi variabler, der er erklæret inde i funktioner, ikke kan kaldes direkte uden for funktionen, som de er i det lokale navneområde. Uvillig til at foretage yderligere ændringer på grund af den lamme fejl besluttede jeg at vende tilbage til den samme kode, som jeg havde ramt mit hoved fra starten.

Men til min fuldstændige vantro fungerede programmet ikke på samme måde som før. Faktisk fungerede det slet ikke! Jeg kunne simpelthen ikke finde ud af årsagen (og jeg kan stadig ikke!). Jeg var helt deprimeret resten af ​​dagen. Det var som at opleve et mareridt, selv før du sovnede!

Heldigvis og mirakuløst fungerede koden den næste dag, efter at jeg havde foretaget nogle omhyggelige ændringer. Jeg sørgede for, at jeg lavede mange beta-filer (for hver ændring, der blev foretaget) derefter for at undgå et sådant unødvendigt kaos.

Efter et par timer kunne jeg endelig afslutte mit program (men ikke før jeg havde brugt 4 fulde dage). Jeg lavede nogle få ændringer som:

i) at ændre funktionen 'hasNumbers' til 'hasNumbersDot' -funktionen og ekskludere den regex, jeg lavede tidligere i programmet. Dette matchede tasterne mere effektivt, da det ikke havde nogen antagelser og dermed ingen undtagelser. Koden for det er som følger:

ii) udskiftning af regex-tilstand og koden til at hente nøgler fra den rene liste.

iii) at kombinere 'hvis' betingelser i 'eksempler udtrækning' del

iv) materialisering af koden til ordbogstasten

Efter nogle forsøg og fejl kunne jeg også konvertere de opnåede data til en smukt struktureret CSV-fil:

Du kan tjekke mit github-arkiv på min profil for at se den fulde kode til programmet inklusive tekstfilen og csv-filen.

Alt i alt var det en stor oplevelse. Jeg fik at lære så meget ud af dette projekt. Jeg fik også mere tillid til mine færdigheder. På trods af nogle uheldige begivenheder (programmering involverer sådanne ting: P), var jeg endelig i stand til at fuldføre den givne opgave.

En sidste ting! For nylig stødte jeg på en morsom meme angående faser af debugging, som er så relateret til min erfaring, at jeg ikke kan modstå deling. xD

Tak for at du kom hele vejen frem til her (selvom du sprang over det meste for at tjekke det endelige resultat: P).