Makrá v OpenOffice.org 3/VII. – Prevod čísla na text 2.

Július Pastierik  /  04. 05. 2006, 00:00

V dnešnom dieli seriálu o programovaní makier v OpenOffice.org si nielen zlepšíme makro pre prevod čísla na text, ale zároveň si ukážeme, ako ho môžeme volať tými najrôznejšími spôsobmi.

Na úvod si pripomeňme, že minule sme si naprogramovali makro pre prevod čísla na text s tým, že sme zatiaľ neuvažovali o tzv. finančných číslach, t.j. tvare, keď sa číslovka jedna vypisuje aj pri stovkách či iných rádoch (jednosto, jedentisíc, …). Toto však v mnohých prípadoch nevyhovuje a preto si uvedieme teraz makro, v ktorom je tento prípad ošetrený. Pochopiteľne, makro upravíme tak, aby sme mohli dostať obidva požadované tvary. Za týmto účelom pridáme do funkcie „daj_slovne“ druhý – nepovinný parameter, pomocou ktorého budeme určovať typ výsledku. Vlastné makro potom môže vyzerať takto:

function daj_slovne(cislo as Long, optional financne as boolean) as string
dim rad as integer ' 1 – tisíc, 2 – milion, 3 – miliarda
dim slovne as string
dim pom_financne as boolean
dim analyza as long

 if not IsMissing(financne) then ' Parameter typu výsledku je zadaný
  pom_financne=financne
 else ' Parameter nie je zadaný
  pom_financne=FALSE ' štandardne nebudeme prevádzať na finančné číslo
 endif

 slovne=""

 if cislo=0 then
  ' Osobitne musíme ošetriť číslo „nula“
  slovne="nula"
 else
  rad=0
  do while cislo<>0
   ' z čísla vyberieme posledné tri číslice
   analyza=cislo mod 1000
   ' ktoré prevedieme na text
   slovne=slovne_stovky(analyza, rad)+slovne
   ' číslo zmenšíme o už spracovanú časť
   cislo=int(cislo/1000)
   ' a pridáme text rádu, ktorý budeme spracovávať v ďalšom kroku cyklu
   if cislo<>0 then
    rad=rad+1
    slovne=slovne_rady(cislo mod 1000, rad)+slovne
   endif
  loop

  if pom_financne then ' Úprava v prípade, že píšeme "finančné" číslovky
   ' Úprava výsledku, ak chceme finančné číslo
   if (analyza>=100) and (analyza<=199) then
    ' úprava výsledku pre stovky
    slovne="jedno"+slovne ' jednosto...
   endif
   if (analyza=1) and (rad=0) then
    ' úprava výsledku, ak sme prevádzali na text číslo jedna, lebo
    ' číslovka "jeden" sa skloňuje, t.j. vo financiách sa píše "jedna koruna".
    slovne="jedna"
   endif
   if (analyza=1) and (rad>0) then
    ' úprava výsledku pre ostatné rády
    select case rad
     case 1, 2, 4, 6, 8
      slovne="jeden"+slovne ' jedentisíc, jedenmilión, …
     case 3, 5, 7, 9
      slovne="jedna"+slovne ' jednamilarda, …
    end select
   endif
  endif
 endif

 daj_slovne=slovne
end function

Teraz si ukážeme, ako budeme toto makro volať tými najrôznejšími spôsobmi. Podobne, ako sme to urobili pri makrách pre formátovanie textu, aj teraz si rozdelíme podprogramy do rôznych modulov. Už naprogramované funkcie uložíme do modulu „ Cislo_Slovom“ a nasledujúce podprogramy do modulu „Module1“ v zložke „Standart“. Robíme to z toho dôvodu, že pri volaní makier v Calcu je potrebné, aby sa tieto nachádzali v tejto zložke.

Pretože si teraz predstavujeme vstupnú funkciu „InputBox “, ukážeme si túto možnosť ako prvú s tým, že prevedené číslo ihneď vložíme do písaného textu:

sub Vloz_cislo_slovom
dim cislo_s as string
dim cislo as long
dim dokument, dispecer as object
dim argumenty(0) as new com.sun.star.beans.PropertyValue

 cislo_s= inputbox("Zadajte celé číslo, ktoré chcete vložiť slovom:","Vloženie čísla slovom","")
 if cislo_s<>"" then
  ' ak vôbec zadáme nejaký údaj, tak ho prevedieme na text
  cislo=val(cislo_s)
  dokument=ThisComponent.CurrentController.Frame
  dispecer=createUnoService("com.sun.star.frame.DispatchHelper")
  argumenty(0).Name = "Text"
  argumenty(0).Value = Cislo_Slovom.Daj_Slovne(cislo)
  ' a vložíme ho do textu na aktuálnu pozíciu
  dispecer.executeDispatch(dokument, ".uno:InsertText", "", 0, argumenty())
 endif
end sub

Ešte praktickejšie riešenie je však také, že si napíšeme číslo priamo do dokumentu, označíme ho do bloku a napr. po stlačení niektorej klávesovej skratky, ku ktorej si priradíme nasledujúce makro ho ihneď prepíšeme jeho slovným znením:

sub Vloz_cislo_slovom
dim cislo_s as string
dim cislo as long
dim dokument, vyber, dispecer as object

dim argumenty(0) as new com.sun.star.beans.PropertyValue

 dokument=thisComponent ' aktuálny dokument
 vyber=dokument.getCurrentSelection() ' aktuálny vyber

 ' Ak je počet označených častí nenulový
 if vyber.getCount()>0 then
  ' Vyberieme označený reťazec a orežeme ho o okrajové medzery
  cislo_s=trim(vyber.getByIndex(0).getString())
 
 if cislo_s<>"" then
   ' ak sme niečo označili, tak to prevedieme na text
   cislo=val(cislo_s)
   dokument=ThisComponent.CurrentController.Frame
   dispecer=createUnoService("com.sun.star.frame.DispatchHelper")
   argumenty(0).Name = "Text"
   argumenty(0).Value = Cislo_Slovom.Daj_Slovne(cislo)
   ' a vložíme ho do textu na aktuálnu pozíciu
   dispecer.executeDispatch(dokument, ".uno:InsertText", "", 0, argumenty())
  endif
 endif

end sub

Úplne najpohodlnejšie riešenie je však také, že napíšeme číslo do dokumentu a bez toho, aby sme ho označovali do bloku ho napr. po stlačení klávesovej skratky prepíšeme jeho slovným znením. Na tento účel však najprv musíme sami vyhľadať a označiť posledne vložené slovo pomocou takejto funkcie:

function posledne_slovo (kurzor as object) as string
' funkcia vráti posledne napísané slovo a zároveň ho označí do bloku
dim poms as string
dim slovo as boolean
dim OddelovaceSlov as string

 OddelovaceSlov=" "+chr(&HA0)+chr(&H09)+chr(&H0A)+chr(&H0D)
 OddelovaceSlov=OddelovaceSlov+"-/.,!?;…"
 OddelovaceSlov=OddelovaceSlov+"()[]{}"
 poms=""
 slovo=false

 do while (not kurzor.isAtStartOfLine) and (not slovo)
  ' pokiaľ nie sme na začiatku riadku a nie sme ešte na začiatku slova
  ' tak sa presunieme o jeden znak doľava s tým, že označíme tento znak do bloku
  kurzor.goleft(1,true)
  ' označené slovo si uložíme do pomocnej premennej
  poms=kurzor.getstring
  ' ak sme našli oddeľovač slov, tak sme na začiatku slova
  slovo=instr(OddelovaceSlov,left(poms,1))
 loop

 if slovo and (len(poms)>1) then
  ' ak sme boli na začiatku slova (a ak sme vôbec niečo označili)
  ' tak musíme tento oddeľujúci znak z nájdeného slova vylúčiť, t.j.
  ' vrátime sa o krok späť
  kurzor.goright(1,true)
  poms=kurzor.getstring
 endif

 posledne_slovo=poms
end function

Vlastné makro pre vloženie slovného znenia môže potom vyzerať takto:

sub Vloz_cislo_slovom
dim kurzor, doc as object
dim cislo as long
dim scislo as string

 doc=ThisComponent.CurrentController
 kurzor=doc.getViewCursor() ' Aktuálna pozícia kurzora

 scislo=posledne_slovo(kurzor)
 cislo=val(scislo)

 if trim(str(cislo))=scislo then
  scislo=Cislo_Slovom.Daj_Slovne(cislo)
  kurzor.SetString(scislo) ' označené číslo prepíšeme jeho slovným znením
 endif

 kurzor.goright(len(scislo),false) ' nakoniec odznačíme blok (zostal označený aj po vložení textu)

end sub

Ako ste si mohli všimnúť, funkcia pre hľadanie posledného slova ukončí jeho hľadanie, ak narazí na nejaký znak, ktorý považujeme za oddeľovač slov a preto musíme procedúru „Vloz_cislo_slovom“ volať ihneď po napísaní príslušného čísla bez toho, aby sme za ním zadali čo i len medzeru.

Nakoniec si naprogramujeme funkciu pre vloženie slovného znenia čísla v module Calc. Pretože niekedy požadujeme, aby vložené slovo začínalo veľkým písmenom, vylepšíme ju aj o takýto nepovinný paramater:

function Slovom(Cislo as Long, optional Financne, optional Velke)
dim nazov as string
dim pom_fin, pom_velke as boolean

 ' štandardne budeme predpokladať, že chceme finančné číslo
 pom_fin=TRUE
 if not IsMissing(Financne) then ' Parameter je zadaný
  if TypeName(Financne)="String" then
   ' ak je vstupná hodnota logická, Calc ju odovzdá ako reťazec „true“ alebo „false“
   if uCase(Financne)="TRUE" or uCase(Financne)="FALSE" then
    pom_fin=Financne
   endif
  endif
 endif

 ' štandardne budeme predpokladať, že chceme začínať veľkým písmenom
 pom_velke=TRUE
 if not IsMissing(Velke) then ' Parameter je zadaný
  if TypeName(Velke)="String" then
   if uCase(Velke)="TRUE" or uCase(Velke)="FALSE" then
    pom_velke=Velke
   endif
  endif
 endif

 ' číslo prevedieme na text
 nazov=Cislo_Slovom.Daj_Slovne(cislo,pom_fin)

 if pom_velke then
  ' a ak chceme prvé písmeno veľké, tak to zmeníme
  nazov=uCase(left(nazov,1))+right(nazov,len(nazov)-1)
 endif

 Slovom=nazov
end function

Pri vlastnom volaní tejto funkcie si musíme uvedomiť, že nepovinné parametre sa „dopĺňajú“ zľava doprava, t.j. ak zadať tretí parameter „Velke“, musíme zadať aj druhý parameter „Financne“. Jednotlivé možnosti si však podrobnejšie preskúmajte ako domácu úlohu.

Skončili sme tretiu sériu nášho seriálu o programovaní makier v OpenOffice.org. Teraz môžete protestovať, že sme ešte neprebrali poslednú možnosť interaktívnych vstupov – dialógy. Vzhľadom na rozsah tejto problematiky im však budeme venovať celú nasledujúcu sériu článkov. Štvrtú sériu začneme, ako inak, makrami pre vkladanie nezalomiteľnej medzery za jednoznakové predložky s tým, že rozšírime možnosti OpenOffice.org o ich automatické vkladanie už počas písania (podobne, ako to majú konkurenčné produkty) a navyše do makra postupne zabudujeme možnosť vkladania „pružnej“ nezalomiteľnej medzery, čo v súčasnosti nedokážu ani najznámejšie platené kancelárske programy.

Pre všetkých záujemcov sme zároveň pripravili PDF verziu práve ukončenej tretej časti seriálu o programovaní makier v OpenOffice.org: makra_v_ooo_3.pdf (
378kB, MD5 kontrolný súčet – 228D7C86E82E9173CCD131BA912A2786). Ako prílohy sú na príslušných stranách priamo v ňom vložené aj zdrojové texty makier v TXT formáte.

Neprehliadnite: