こんな埼「玉」修正してやるぅ

Twitter を眺めていたら

という tweet を見かけた。 これは Adobe Acrobat Distiller の不具合なんだそうで,2019年9月には既に話題に登っているのだが,2020年7月の時点でも修正されていないようだ。

Adobe Acrobat Distiller が見捨てられてるのか,それとも「日本語」が見捨てられているのか…

【2021-0129 追記】 PostScript プリンタドライバ経由で PostScript データを吐き出すと似たようなことが起きるらしい。もしかしたら Distiller の不具合ってこれが原因? かも。

閑話休題 (それはさておき) 。 問題となっているのは「康熙部首(kangxi radicals)」と呼ばれる漢字の部首を集めた以下の Unicode 符号点領域である。

“Kangxi radical - Wikipedia” より抜粋

要するに,これらの領域の文字を本来の符号点に変換してやればいいわけだ。 件の tweet のスレッドを見ると,幸いにも Unicode の NFKC 正規化で変換可能らしい。

試しに以下のコードを組んで

package main

import (
    "fmt"

    "golang.org/x/text/unicode/norm"
)

func main() {
    for r := rune(0x2f00); r <= 0x2fd5; r++ {
        rr := []rune(norm.NFKC.String(string([]rune{r})))
        if r != rr[0] {
            fmt.Printf("%#U -(NFKC)-> %#U\n", r, rr[0])
        }
    }
}

実行してみると

$ go run sample1.go 
U+2F00 '⼀' -(NFKC)-> U+4E00 '一'
U+2F01 '⼁' -(NFKC)-> U+4E28 '丨'
U+2F02 '⼂' -(NFKC)-> U+4E36 '丶'
...
U+2F5F '⽟' -(NFKC)-> U+7389 '玉'
...
U+2FD4 '⿔' -(NFKC)-> U+9F9C '龜'
U+2FD5 '⿕' -(NFKC)-> U+9FA0 '龠'

てな出力(一部割愛)になって,ちゃんと変換されていることが分かる。

ただし Unicode 正規化は副作用があるので安直には使えない。 となると,前回の「かなカナ変換」で紹介した方法が使えるかな。

変換後の符号点の値は散らばっていて且つ数も多く手作業でコードを書くのは不毛なので,まずは unicode.SpecialCase を生成するコードを書いてみよう(笑)

package main

import (
    "fmt"
    "strconv"

    "golang.org/x/text/unicode/norm"
)

func main() {
    fmt.Println("var KangxiRadicals = unicode.SpecialCase{")
    for kr := rune(0x2f00); kr <= 0x2fd5; kr++ {
        rr := []rune(norm.NFKC.String(string([]rune{kr})))
        if kr != rr[0] {
            fmt.Printf("\tunicode.CaseRange{%#[1]x, %#[1]x, [unicode.MaxCase]rune{%#[2]x - %#[1]x, 0, 0}}, // %#[1]U -> %#[2]U\n", kr, rr[0])
        }
    }
    fmt.Println("}")
}

これを実行するとこんなコードが得られる(一部割愛)。

$ go run sample1b.go
var KangxiRadicals = unicode.SpecialCase{
    unicode.CaseRange{0x2f00, 0x2f00, [unicode.MaxCase]rune{0x4e00 - 0x2f00, 0, 0}}, // U+2F00 '⼀' -> U+4E00 '一'
    unicode.CaseRange{0x2f01, 0x2f01, [unicode.MaxCase]rune{0x4e28 - 0x2f01, 0, 0}}, // U+2F01 '⼁' -> U+4E28 '丨'
    unicode.CaseRange{0x2f02, 0x2f02, [unicode.MaxCase]rune{0x4e36 - 0x2f02, 0, 0}}, // U+2F02 '⼂' -> U+4E36 '丶'
    ...
    unicode.CaseRange{0x2f5f, 0x2f5f, [unicode.MaxCase]rune{0x7389 - 0x2f5f, 0, 0}}, // U+2F5F '⽟' -> U+7389 '玉'
    ...
    unicode.CaseRange{0x2fd4, 0x2fd4, [unicode.MaxCase]rune{0x9f9c - 0x2fd4, 0, 0}}, // U+2FD4 '⿔' -> U+9F9C '龜'
    unicode.CaseRange{0x2fd5, 0x2fd5, [unicode.MaxCase]rune{0x9fa0 - 0x2fd5, 0, 0}}, // U+2FD5 '⿕' -> U+9FA0 '龠'
}

あとはこれを組み込んで使えばいいだけ。 たとえばこんな感じに使える。

func unicodePrint(s string) {
    ss := []string{}
    for _, r := range s {
        ss = append(ss, fmt.Sprintf("{%#U}", r))
    }
    fmt.Println(strings.Join(ss, " "))
}

func main() {
    saitama := "埼⽟"
    unicodePrint(saitama)
    unicodePrint(strings.ToUpperSpecial(KangxiRadicals, saitama))
}

これを実行すると

go run sample2.go
{U+57FC '埼'} {U+2F5F '⽟'}
{U+57FC '埼'} {U+7389 '玉'}

となる。 よーし,うむうむ,よーし。

ブックマーク

参考図書

photo
プログラミング言語Go
アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)
丸善出版 2016-06-20 (Release 2021-07-13)
Kindle版
B099928SJD (ASIN)
評価     

Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想はこちら

reviewed by Spiegel on 2021-05-22 (powered by PA-APIv5)