diff options
author | Varriount <Varriount@users.noreply.github.com> | 2015-01-17 18:53:46 -0500 |
---|---|---|
committer | Varriount <Varriount@users.noreply.github.com> | 2015-01-17 18:53:46 -0500 |
commit | eb929bd61c94fc5acf7e384502706fc41a4df2fd (patch) | |
tree | 69ba617482f1ef5670d189daf9de4ec5a083a113 /lib | |
parent | 9847f762e4bc6e01a3303b42a48d576a6751477d (diff) | |
parent | ae7ca46a092204e7dbfb642309600f036de65e6e (diff) | |
download | Nim-eb929bd61c94fc5acf7e384502706fc41a4df2fd.tar.gz |
Merge pull request #1842 from def-/unicode-reversed
Add reversed proc to unicode module
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/unicode.nim | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index c2eb001f6..b892ec8b4 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1194,6 +1194,17 @@ proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true +proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = + ## returns true iff `c` is a Unicode combining character + var c = RuneImpl(c) + + # Optimized to return false immediately for ASCII + return c >= 0x0300 and (c <= 0x036f or + (c >= 0x1ab0 and c <= 0x1aff) or + (c >= 0x1dc0 and c <= 0x1dff) or + (c >= 0x20d0 and c <= 0x20ff) or + (c >= 0xfe20 and c <= 0xfe2f)) + iterator runes*(s: string): Rune = ## iterates over any unicode character of the string `s`. var @@ -1220,9 +1231,48 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = if result != 0: return result = a.len - b.len +proc reversed*(s: string): string = + ## returns the reverse of `s`, interpreting it as unicode characters. Unicode + ## combining characters are correctly interpreted as well: + ## + ## .. code-block: + ## assert reversed("Reverse this!") == "!siht esreveR" + ## assert reversed("先秦兩漢") == "漢兩秦先" + ## assert reversed("as⃝df̅") == "f̅ds⃝a" + ## assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" + var + i = 0 + lastI = 0 + newPos = len(s) - 1 + blockPos = 0 + r: Rune + + template reverseUntil(pos): stmt = + var j = pos - 1 + while j > blockPos: + result[newPos] = s[j] + dec j + dec newPos + blockPos = pos - 1 + + result = newString(len(s)) + + while i < len(s): + lastI = i + fastRuneAt(s, i, r, true) + if not isCombining(r): + reverseUntil(lastI) + + reverseUntil(len(s)) + when isMainModule: let someString = "öÑ" someRunes = @[runeAt(someString, 0), runeAt(someString, 2)] compared = (someString == $someRunes) assert compared == true + + assert reversed("Reverse this!") == "!siht esreveR" + assert reversed("先秦兩漢") == "漢兩秦先" + assert reversed("as⃝df̅") == "f̅ds⃝a" + assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" |