This worked for me
import os, unicode
proc crossOut(text: string): string =
var crossedOut = newStringOfCap(text.len * 2)
for rune in text.runes:
crossedOut.add(rune)
crossedOut.add("\u0336")
return crossedOut
let
inputText = "Hello Żółć"
crossedOutText = crossOut(inputText)
echo crossedOutText
let outputFile = "crossed_out_text.txt"
writeFile(outputFile, crossedOutText)
Result: H̶e̶l̶l̶o̶ ̶Ż̶ó̶ł̶ć̶
Most operations made on strings are not Unicode aware, unless you ask for it. Iterating over a string gives you bytes which don't necessarily correspond to distinct symbols. If a multibyte symbol (represented by the Rune type in Nim's standard library) suddenly gets some other data between its bytes, you get all kinds of crazy output.
import zero_functional, unicode
const test = "Ijon Tichy zgubił swoją ulubioną kurtkę z ćwiekami podczas swojej ostatniej podróży przez czasoprzestrzeń."
let asciiString = test --> fold("",
(a.add(it); a.add("\u0336"); a)
)
echo asciiString
let unicodeString = test.runes() --> fold("",
(a.add(Rune(0x0336)); a.add(it); a)
)
echo unicodeString
Output:
I̶j̶o̶n̶ ̶T̶i̶c̶h̶y̶ ̶z̶g̶u̶b̶i̶Ō¶̶ ̶s̶w̶o̶j̶ȶ
̶ ̶u̶l̶u̶b̶i̶o̶n̶ȶ
̶ ̶k̶u̶r̶t̶k̶ȶ̶ ̶z̶ ̶ȶ̶w̶i̶e̶k̶a̶m̶i̶ ̶p̶o̶d̶c̶z̶a̶s̶ ̶s̶w̶o̶j̶e̶j̶ ̶o̶s̶t̶a̶t̶n̶i̶e̶j̶ ̶p̶o̶d̶r̶̶³̶Ō¶¼̶y̶ ̶p̶r̶z̶e̶z̶ ̶c̶z̶a̶s̶o̶p̶r̶z̶e̶s̶t̶r̶z̶e̶Ō¶̶.̶
̶I̶j̶o̶n̶ ̶T̶i̶c̶h̶y̶ ̶z̶g̶u̶b̶i̶ł̶ ̶s̶w̶o̶j̶ą̶ ̶u̶l̶u̶b̶i̶o̶n̶ą̶ ̶k̶u̶r̶t̶k̶ę̶ ̶z̶ ̶ć̶w̶i̶e̶k̶a̶m̶i̶ ̶p̶o̶d̶c̶z̶a̶s̶ ̶s̶w̶o̶j̶e̶j̶ ̶o̶s̶t̶a̶t̶n̶i̶e̶j̶ ̶p̶o̶d̶r̶ó̶ż̶y̶ ̶p̶r̶z̶e̶z̶ ̶c̶z̶a̶s̶o̶p̶r̶z̶e̶s̶t̶r̶z̶e̶ń̶.
A nice article on the topic: Unicode is Kind of Insane
Rust people usually treat strings with the duly respect, so they have a few detailed articles, such as this one: https://fasterthanli.me/articles/working-with-strings-in-rust