Zamenjava vejic in pik v številkah z regularnimi izrazi

Trenutno delam na letnem poročilu. Z ekipo ga prevajamo v angleščino. Na srečo ni prvič in v prejšnjih letih smo uporabljali pomnilnik prevodov (translation memory), zato lahko recikliramo precejšnji del besedila, predvsem računovodski del, ki je sploh čista veselica z izrazi in formulacijami (usredstvovati, prihodkovati, uskupinjevanje in podobne cvetke; o tem moram kdaj več napisati).

V letnem poročilu je seveda tudi kup zneskov, ki načeloma nimajo kaj dosti s prevodom, razen – angleščina ima ločila tisočic in decimalk ravno obratno kot večina evropskih jezikov (za drugod pa ne vem; je treba kdaj raziskati). Pri nas vejica ločuje celi del števila in decimalke, pika pa tisočice za lažje branje. V angleščini je pa ravno obratno. Torej:

Slovenščina in dr.1.234,56
Angleščina1,234.56

Ajde, recimo da ni ravno življenjsko pomembno tole zamenjat v prevodu, saj je razvidno, kaj je mišljeno. Ampak hočemo narediti dober izdelek, zato bomo seveda zamenjali pike in vejice.
Ročno je to pravo sizifovstvo. Urejevalniki besedil, kot je Word, imajo funkcijo za iskanje in zamenjavo (search and replace), a če vse vejice zamenjamo s pikami, smo naredili več škode kot koristi, saj nočemo zamenjati stavčnih ločil.

Tule pridejo na vrsto t.i. regularni izrazi (regular expressions ali regex), ki so skoraj sam svoj jezik. Regularni izrazi nam omogočajo, da z določenim naborom posebnih znakov opišemo, kaj iščemo. Pogosto se uporabljajo v okviru raznih programskih jezikov, saj je sintaksa regularnih izrazov standardizirana. Pogosto se prav z njihovo pomočjo ugotavlja, če je e-poštni naslov pravilno oblikovan, torej če vsebuje afno, nekaj pred njo in nekaj za njo, v slednjem delu pa mora biti vsaj ena pika. Tovrsten regularni izraz (z dodatnimi omejitvami) je denimo:

\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b
Vir; tam je še več primerov, kako se stvar hitro da zakomplicirati.

Tule ne bom imel uvodnega tečaja regularnih izrazov, saj poznam le grobe osnove. Za zamenjavo pik in vejic več tudi ni potrebno, vsaj v neki osnovi obliki.

V našem primeru iščemo vejice oz. pike, kjer sta levo in desno številka. Vzemimo najprej piko. Naslednji izraz bo iskal pike, ki imajo številko tik pred in za sabo. Za to mora Wordovem okencu za iskanje biti vključena možnost Uporabi nadomestne vzorce ali v angleškem Use wildcards, ki se skriva med dodatnimi možnostmi, ko kliknemo Več/More v omenjenem okencu.
([0-9]).([0-9])

Kot vidimo, je osrednji del pika. Da iščemo številke, povemo tako, da damo želeni nabor (naštejemo enega za drugim npr. [123abc], kar bo iskalo le teh šest znakov) ali obseg znakov (kot v tem primeru z vezajem vmes) v oglate oklepaje. Navadni oklepaji pa so pomembni za del, kjer bomo izvedli zamenjavo. Označujejo sklope, s katerimi lahko operiramo pri zamenjavi.

Če bi rezultat zgornjega iskanja le zamenjali z vejico, bi izbrisalo številki levo in desno, zato moramo rezultat iskanja ustrezno vstaviti nazaj v dokument.  Sklope, ki smo jih pri iskanju dali v navadne oklepaje, pri zamenjavi uporabimo tako, da za levo poševnico (backslash \) navedemo zaporedno številko sklopa. Ker številk seveda nočemo zamenjati, bo v tem primeru torej:
\1,\2

Ta funkcionalnost regularnih izrazov omogoča številna napredna iskanja in zamenjave pri urejanju dokumentov, recimo da seznam oseb, ki so navedene v obliki priimek, ime brez ročnega urejanja zamenjamo v obliko ime priimek.

Nazaj k vejicam in pikam. Načeloma lahko omenjeno zamenjavo opravimo po celem dokumentu, a ker dokumenti običajno vsebujejo ločilo tisočic in decimalk hkrati, bi s tem naredili več škode kot koristi, saj bi vse pike v številkah zamenjali z vejicami, potem pa na podoben način ne bi mogli ustreznih vejic zamenjati  pikami oz. vsaj ne na dovolj zanesljiv način. Zato sam najraje uporabljam "vmesni" znak, t.j. nek znak, ki se v dokumentu ne pojavlja ali za katerega lahko zagotovo domnevam, da se ne bo pojavil med dvema številkama. Težko je določiti znak, ki bi bil univerzalno uporaben v ta namen, saj se po različnih strokah pojavljajo zelo raznovrstne oblike zapisov številk. Za ta primer bom vzel znak za paragraf §, v kakšnem pravnem besedilu pa se mogoče ne bi obnesel. Pogosti znaki, kot so #, $, %, &, ^ ipd. so vsi kar dobri kandidati, znajo pa spet biti težavni v določenih primerih: # je lahko težaven pri besedilih glede mobilnih telefonov, $ ko gre za dolarje, % kjer se navaja veliko odstotnih podatkov, & ni redek namesto veznika in, ^ se mogoče uporablja kot  zapis potence. To so resda skrajni in malo verjetni primeri, ampak nepremišljena uporaba samodejne zamenjave vseh pojavitev zna hitro povzročiti napako v besedilu, ki se bo mogoče odkrila, ko bo že prepozno. Zato torej pazljivo z izbiro vmesnega znaka, še bolj pa funkcije Zamenjaj vse.

Dovolj pridige. Za zamenjavo pik in vejic so potrebni torej trije koraki:
NajdiZamenjaj z
1. Najdi vse pike med številkami
in jih zamenjaj z vmesnim znakom, tu §.
([0-9]).([0-9])\1§\2
2. Najdi vse vejice med številkami
in jih zamenjaj s pikami.
([0-9]),([0-9])\1.\2
3. Najdi vse § med številkami
in jih zamenjaj z vejicami.
([0-9])§([0-9])\1,\2

Pa še makro za Word, ki gre čez cel dokument in vse to opravi. Za vmesni znak prav tako uporablja §, ki ga po potrebi lahko zamenjate (na dveh mestih).

Pozor: ta makro uporabljate na lastno odgovornost. V praksi sem ga uporabil samo enkrat in ni nujno, da se bo v tej obliki vedno obnesel.
Sub SwitchCommaAndDot()
Selection.Find.ClearFormatting
 With Selection.Find
 .Text = "([0-9]).([0-9])"
 .Replacement.Text = "\1§\2"
 .Forward = True
 .Wrap = wdFindContinue
 .Format = False
 .MatchCase = False
 .MatchWholeWord = False
 .MatchAllWordForms = False
 .MatchSoundsLike = False
 .MatchWildcards = True
 End With
 Selection.Find.Execute Replace:=wdReplaceAll
 Selection.Find.ClearFormatting
 With Selection.Find
 .Text = "([0-9]),([0-9])"
 .Replacement.Text = "\1.\2"
 .Forward = True
 .Wrap = wdFindContinue
 .Format = False
 .MatchCase = False
 .MatchWholeWord = False
 .MatchAllWordForms = False
 .MatchSoundsLike = False
 .MatchWildcards = True
 End With
 Selection.Find.Execute Replace:=wdReplaceAll
 Selection.Find.ClearFormatting
 With Selection.Find
 .Text = "([0-9])§([0-9])"
 .Replacement.Text = "\1,\2"
 .Forward = True
 .Wrap = wdFindContinue
 .Format = False
 .MatchCase = False
 .MatchWholeWord = False
 .MatchAllWordForms = False
 .MatchSoundsLike = False
 .MatchWildcards = True
 End With
 Selection.Find.Execute Replace:=wdReplaceAll

Ni komentarjev:

Objavite komentar