Čudno slovo ć
Da li vam se nekad desilo da u Word dokumentu vidite normalno slovo ć, ali se ono pri izvozu u tekst ili kopiranju u neki drugi program pojavi kao c’, pri čemu taj drugi znak zapravo i nije apostrof? Istražili smo ovaj problem i pronašli rešenje

Na “čudno ć” povremeno naiđemo u tekstu nekog saradnika, i najzad smo shvatili kako ono nastaje: saradnik je najverovatnije koristio Google Translate, pa iz njega kopirao blok teksta u Word dokument – eto načina da prepoznate ne baš originalni prilog. Kada takav dokument snimite kao Text only dobićete ć? – upitnik znači da se Word nije baš najbolje snašao sa izvozom. Naš standardni VBA program za izvoz teksta iz Word-a pretvori ga u c´, pri čemu drugi znak samo liči na apostrof – to je kod 0xB4 ili dekadno 180, što je u ASCII tabeli označeno kao acute accent, dakle “kvaka na c”. U neku ruku sve to deluje logično ali pravi problem, s tim što Google Translate nekada ć napiše normalno, a nekada upotrebi ovu čudnu kombinaciju kodova.
Pogled na Unicode
VBA program sa slike 1 pokazuje da se u tekstu javlja najpre obično c a iza njega kod 0x301 (769 dekadno). Pošto Word memoriše dokumente koristeći Unicode, možemo da pogledamo Unicode tabelu i tamo ćemo naći da kod 769 predstavlja Combining Acute Accent. Stvari počinju da bivaju jasnije – slovo ć je napisano kao c na koje se naknadno dodaje kvačica, kao što se nekad radilo na matričnim štampačima koji nisu imali ugrađena YU slova. Zašto bi Google Translate ubacio takvo slovo kad na raspolaganju ima pravo ć (čiji je Unicode 0x107, odnosno 263 dekadno; u tabeli se zove latin small letter c with acute) ostaje nejasno. Uz malo dodatnog eksperimentisanja pokazalo se da se i ostala naša slova mogu kreirati kao kombinacija običnog slova c, s i z i odgovarajuće kvačice, samo što se kod njih koristi kod 0x30C (dekadno 780) koji se zove Combining Caron. Recimo, kada iza koda za obično c (ASCII kod 99) stavi kod 780, dobija se “čudno slovo” koje na ekranu izgleda kao č, mada se izvozi kao dva karaktera. Nismo primetili da Google Translate ikada ubacuje u tekst ova slova – iz nekog razloga je samo ć ponekad prikazano na čudan način.
Kolega Aleksandar Šušnjar je napravio tabelu Unicode oznaka svih naših slova (slika 2), u raznim varijantama. Primetite da slova lj, nj i dž imaju posebne Unicode pozicije, i čak se kod velikih pojavljuju varijante LJ, NJ i DŽ a onda Lj, Nj i Dž. Nije predmet ove priče, ali je dobro znati. Korišćenjem ovih oznaka bi se obezbedilo korektno sortiranje teksta na srpskom.
Znak po znak…
Pošto smo postavili dijagnozu, tretman je prilično jasan. Treba proći kroz dokument pa, gde god se nađe slovo c pa iza njega kod 769, svesti to na obično ć. Recimo, ubacimo ć a izbacimo taj dodatni “apostrof” i to je to. Kao u listingu 3.
Zvučalo je jednostavno, ali ne radi – program ne zameni ni jedno čudno ć. Debager pokazuje da program uopšte ne ulazi u blok if naredbe. Dalja analiza ukazuje na to da to čudno ć i jeste i nije kombinacija dva slova. Naime, dok smo u listingu 1 koristili kolekciju ActiveDocument.Words, dakle sve reči u dokumentu, čudno ć je zaista predstavljalo dva slova. Ali kad smo prešli na kolekciju ActiveDocument.Characters, dakle sve karaktere u dokumentu, čudno ć se pojavljuje kao jedno (ali neobično) slovo.
Bejzik naredba znak = ActiveDocument.Characters(brojac) bi po logici stvari trebalo da vrati jedan znak, ali u ovom slučaju ona vrati string od dva znaka. Slovo c je prvi, a kod 769 drugi. Treba prepoznati takvu situaciju i onda na isto mesto upisati jedan znak, slovo ć odnosno kod 263. To rešenje prikazano je na slici 4 – funkcioniše korektno, ali ne baš slavno.
Rad sa kolekcijom karaktera u dokumentu nije preporučljiv jer je – spor. Pri tom reč spor treba ozbiljno shvatiti: nije da ćete sačekati par sekundi, nego ćete čekati i čekati. Recimo, obrada teksta od oko 24000 znakova (ovomesečni izveštaj sa CES-a), iako u njemu nije bilo ni jednog “čudnog ć”, potrajala je, na savremenom i brzom računaru, lepih 19 minuta. Obrada se može ubrzati tako što se na početku ukine osvežavanje ekrana (Application.DisplayAlerts = False i Application.ScreenUpdating = False) ali je i posle toga rad sporiji nego što biste želeli.
Finalna zamena
Do konačnog rešenja došli smo primenom Find / Replace procedure, kao u listingu 5. Čak i na veoma dugačkom tekstu posao se završi praktično trenutno. Ipak, treba primetiti da je ovde menjano samo malo ć, pošto smo jedino njega primetili u praktičnim situacijama. Ako bismo želeli da obradimo i ostala kombinovana slova, dakle čšž, pa onda i velika slova ČĆŽŠ, zamena bi morala da se ponovi nekoliko puta, mada verujemo da bi postupak i tada trajao prihvatljivo malo vremena.
Listing 1: Analiza teksta u Word dokumentu
Public Sub proba_izvoza()
Dim rec As String, i As Long
rec = ActiveDocument.Words(1)
Debug.Print rec
For i = 1 To Len(rec)
Debug.Print Hex((AscW(Mid(rec, i, 1)))); " ";
Next i
Debug.Print
End Sub
Slika 2: Unicode oznake naših slova

Listing 3: (Neuspešan) pokušaj zamene slova
dim brojac as long, znak as string
brojac = 1
While brojac <= ActiveDocument.Characters.Count
znak = ActiveDocument.Characters(brojac)
if brojac>1 and AscW(znak) = 769 Then
ActiveDocument.Characters(brojac-1) = "ć"
ActiveDocument.Characters(brojac).Delete
End If
brojac = brojac + 1
Wend
Listing 4: Uspešna, ali spora zamena čudnog ć
Public Sub cudnoslovoc()
Dim brojac As Long, znak As String
brojac = 1
While brojac <= ActiveDocument.Characters.Count
xnak = ActiveDocument.Characters(brojac)
If Len(znak) > 1 And AscW(Right(znak, 1)) = 769 Then
ActiveDocument.Characters(brojac) = "ć"
End If
brojac = brojac + 1
Wend
End Sub
Listing 5: Efikasna zamena slova korišćenjem Find / Replace
Public Sub cudnoslovoc()
Dim doc As Document
Dim rng As Range
Dim findText As String
Dim replaceText As String
Set doc = ActiveDocument
findText = "c" & ChrW(&H301) ' c + combining acute accent
replaceText = ChrW(&H107) ' ć (normal)
For Each rng In doc.StoryRanges
With rng.Find
.Text = findText
.Replacement.Text = replaceText
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.Execute Replace:=wdReplaceAll
End With
Next rng
End Sub