はじめに
Unicode 正規化って日本語の処理に向いていないというか、ちょっと使いどころが難しいと思いませんか?
ということで、Golang のノーマライゼーション・ライブラリを作ってみました。使えるレベルに仕上がったと思うので GaGa という名前で公開します。
Unicode 正規化に関しては、既に Golang の準標準ライブラリに、
- golang.org/x/text/unicode/norm
- golang.org/x/text/width
というパッケージがありますが、今回作ったものと機能を比較すると以下のような違いがあります。
機能など | gaga | norm | width | 補足 |
---|---|---|---|---|
全角-半角 変換 |
〇 | △ | △ | 詳細は後述しますが、norm と width は期待外れな結果を返します。 |
ひらがな- カタカナ 変換 |
〇 | × | × | 「ひらがな-カタカナ変換器」はノーマライザというよりはトランスレータの類かもしれませんね。 |
大文字- 小文字 変換 |
〇 | × | × | これは Golang の標準ライブラリ strings パッケージでサポートされていますね。これもトランスレータの類でしょうか。 |
濁点・半濁点 の分解合成 |
〇 | △ | △ | これも norm と width は期待外れな振舞いをします。詳細は後述します。 |
文字種別ごとの変換 | 〇 | × | × | gaga は アルファベット、ラテン数字、ラテン記号、ひらがな、カタカナ、かな記号ごとに変換方法を指定できます。 |
パフォーマンス | 〇 | △ | ◎ | 処理時間を比較するとこんな感じです。 gaga : norm : width ≒ 2 : 6 : 1 |
サポートする文字 | △ | ◎ | ◎ | gaga のサポート範囲はラテン文字とひらがなカタカナを中心とする462文字です。 |
ちなみに、Golang の準標準ライブラリの振舞いが期待外れなのは、開発チームや実装に問題があるということではありません。世界中のありとあらゆる文字を取り扱わなければならない Unicode の標準化において、多種多様な文化間のバランスを取りながら最大公約数的に策定せざるを得なかった正規化フォームの仕様が、「かな文字」をネイティブとして扱う我々にとっては完全なものではないということなのだと思います。
目次
- Unicode の 7 種類の「ゴ」について
- Combining characters について
- Unicode 正規化フォームの問題点
- どんなライブラリを作ったのか?
- どのように実装したのか?
- パフォーマンスは良いのか?
- GaGa がサポートする 462文字
Unicode の 7 種類の「ゴ」について
Unicode でカタカナの「ゴ」と書くとき、多くの人はコードポイント U+30B4(名称: KATAKANA LETTER GO)を使うと思います。
ところが歴史的な事情により UNICODE には 3 種類の「濁点マーク」が登録されていて、
3 種類の濁点マーク
グリフ | Unicode | JIS | 名前 |
---|---|---|---|
゛ | U+309B | 212B (JIS X 0208) |
KATAKANA-HIRAGANA VOICED SOUND MARK |
゙ | U+FF9E | DE (JIS X 0201) |
HALFWIDTH KATAKANA VOICED SOUND MARK |
◌゙ | U+3099 | (undefined) | COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK |
これに濁点なしの全角の「コ」と半角の「コ」を組み合わせると、「ゴ」という 1 つの文字を 7 通りの方法で表現できてしまいます。
7 通りの「ゴ」
No. | グリフ | 構成 | コードポイント | 説明 |
---|---|---|---|---|
1 | ゴ | [ ゴ ] | [ U+30B4 ] | [ 濁点付き 全角文字 ] |
2 | コ゛ |
[ コ ] + [ ゛ ] |
[ U+30B3 ] + [ U+309B ] |
[ 濁点なし 全角文字 ] + [ 全角 濁点 ] |
3 | ゴ |
[ コ ] + [ ゙ ] |
[ U+30B3 ] + [ U+FF9E ] |
[ 濁点なし 全角文字 ] + [ 半角 濁点 ] |
4 | ゴ |
[ コ ] + [ ゙ ] |
[ U+30B3 ] + [ U+3099 ] |
[ 濁点なし 全角文字 ] + [ 幅なし 濁点 ] |
5 | コ゛ |
[ コ ] + [ ゛ ] |
[ U+FF7A ] + [ U+309B ] |
[ 濁点なし 半角文字 ] + [ 全角 濁点 ] |
6 | ゴ |
[ コ ] + [ ゙ ] |
[ U+FF7A ] + [ U+FF9E ] |
[ 濁点なし 半角文字 ] + [ 半角 濁点 ] |
7 | ゴ |
[ コ ] + [ ゙ ] |
[ U+FF7A ] + [ U+3099 ] |
[ 濁点なし 半角文字 ] + [ 幅なし 濁点 ] |
上表のグリフ欄の見え方は環境によって変わりますが、筆者の環境(Windows 10 + Chrome 85)では、上記 1 と 4、また 5 〜 7 は見た目上の違いがわかりません。
また、これは特にラテン文字に顕著ですが、プロポーショナルフォントが当たり前になった現代では、全角と半角の違いが昔より分かりにくくなりました。
そして、この「似ているのに異なる」ことが、
- 検索してても見つからない
- 統計を取る際のカテゴライズに苦労する
などといった、地味だけど面倒な問題を引き起こします。
この問題の対処方法はいくつかありますが、
No. | アプローチ | ソリューションの具体例 | 補足 |
---|---|---|---|
1 | 入力制限 | Validation 検査 | 登録フォームなど情報の入口で入力できる文字を制限し、正規形のみを通過させるとてもポピュラーなアプローチ。 |
2 | 選択 | プルダウンメニューなど | 入力制限の一種。選択肢が少ないときは便利。 |
3 | 同値とみなす | DBMS の Collation | 情報の出口での対処方法。データベースの文字セットに照合順序の属性を持たせ、比較の際に例えば半角と全角、大文字と小文字を同値とみなすアプローチ。 |
4 | 形を揃える | Unicode Normalization | 正規化して形を整えてから比較するアプローチ。情報の入口でも適用できるが、Webサイトの登録フォームなどではあまり見かけない。 |
本稿のテーマは上記 4 に関するものです。
誰かがついうっかり「ゴー言語」や「コ゛ー言語」と入力してしまっても、由緒正しい「ゴー言語」ではないからといって、「その文字は入力できません!」などと拒絶するのではなく、そっと優しく正規の形に導いてあげませんか? そのためのライブラリを作りました!という話です。
Combining characters について
上述のとおり、Unicode には、JIS 由来の濁点マーク [゛](U+309B)、[゙](U+FF9E) の他に、端末でレンダリングする際に基底文字に合成してレイアウトされる「幅ゼロの濁点マーク」[◌゙](U+3099) が登録されていて、その名称には "COMBINING" というプレフィクスが付けられています。
(半濁点にも同様に [ ゚ ](U+309A) があります)
普段の生活でこの Combining character (Non-space mark) を使う機会は少ないと思いますが、Unicode 正規化フォームの「正準等価性による分解と合成」においてもキーになる文字なので少しだけ触れておきます。
Combining character のメリット
かつて JIS X 0208 には ヴ という文字はありましたが、ゔ はありませんでした。
JIS X 0213 では ゔ が登録され、他にも、ヷ(濁点付きの [ワ])、カ゚(半濁点付きの [カ])なども登録されました。
ところが、JIS X 0213 に ヷ はあるのに、わ゙ はありません。
また、Unicode への カ゚ の登録は見送られました。見送られた理由は Combining character の U+309A で合成できるから、ということのようです。
整理すると以下のようになります。
特殊な濁点付き文字の例
グリフ (Unicode) |
代用表記 (JIS X 0208) |
JIS X 0213 のサポート |
Unicode のサポート |
補足 |
---|---|---|---|---|
ゔ | う゛ | 〇 | 〇 | |
ヷ | ワ゛ | 〇 | 〇 | |
わ゙ | わ゛ | × | × | グリフ欄: [わ]+[U+3099]で表示 |
カ゚ | カ゜ | 〇 | × | グリフ欄: [カ]+[U+309A]で表示 |
また、以下のような文字も JIS に登録されていません。
(JIS に登録されていないので、当然 Unicode にも登録されていません)
用途 | グリフ Unicode |
代用表記 JIS X 0208 |
補足 |
---|---|---|---|
ジャイアントロボの決め台詞 | マ゙ | マ゛ | グリフ欄: [マ]+[U+3099]で表示 |
一部の官能表現など | ア゙ | ア゛ | グリフ欄: [ア]+[U+3099]で表示 |
近年、アーティスト名の表現方法が多彩になってきていますが、今後、濁音を持たない文字に濁点や半濁点を組み合わせた名前も出てくるかもしれません。
Combining character を使えば、新たにコードポイントを追加しなくても、このような要求を満たすことができます。
Combining character のデメリット
現時点ではまだ普及しているとはいえないことが挙げられるでしょう。
環境によって見え方が変わってしまうのです。
同じプラットフォームで同じアプリケーションを使っていても、フォントにより見え方がまったく違います。
以下は筆者の環境で、ひとつの Excel シート内に、Combining Character を含む同一の文字列をフォントだけ変えて表示した例です。
編集時の挙動もアプリケーションによって違います。
アプリケーションによって、濁点だけを削除することができたり、先行の文字にくっついて削除できなかったりと、違いがあります。
興味がある人は以下の文字列をエディタなどにコピペして試してみてください。
え゚?゚ G゙A゙G゙A゙が゙?゙ |
---|
このように、Combining character はまだまだ普及しているとは言えません。現段階ではキャラクターベースのコミュニケーション用途には向きません。どうしても使いたいという場合は、環境要件を固定するか、特定の環境でラスタライズしたものを共有するなどの対応が必要になるでしょう。
Unicode 正規化フォームの問題点
問題点について述べる前に Unicode 正規化フォーム (Unicode Normalization Form) について簡単に整理しておきます。
まず用語ですが、本稿では以下の用語を使って話を進めます。
用語 | 別名 (かな文字の場合) |
例 | 略称 |
---|---|---|---|
Voicing modifier | 発声修飾子 (濁点または半濁点) |
[ ゛ ] [ ゜ ] | VOM |
Pre-composed character | 合成済み文字 (濁点付き文字) |
[ ゴ ] | Precomp |
Base character | 基底文字 (濁点なし文字) |
[ コ ] | Base |
Combining character | 結合文字 (幅なしのVOM) ※全角と半角のVOMは含まない |
[ ◌゙ ] | Combining |
次に Unicode の「正準等価性」と「互換等価性」について整理します。
正準等価性
まずは、正準等価性です。
正準等価性というのは、かな文字で言えば濁点付き文字(または半濁点付き文字)の等価性のことで、分解と合成により別の等価な文字シーケンスに置き換えることができます。
正準等価性による分解・合成
正規化の種類 | かな文字の挙動 | 例 |
---|---|---|
分解 | Precomp を Base と Combining に分解する。 | [ ゴ ] => [ コ ] + [ ◌゙ ] |
合成 | Base と Combining を Precomp に合成する。 | [ コ ] + [ ◌゙ ] => [ ゴ ] |
本稿のテーマからは逸れますが、ラテン文字のダイアクリティカルマークなども、正準等価性による分解と合成をすることで、これとよく似た変換が行われます。
互換等価性
次に、互換等価性です。
互換等価性は、かな文字で言えば全角と半角の等価性のことです。
分解により、かな文字は全角へ、ラテン文字は半角へ変換されます。
また、かな文字以外では「互換等価性による分解」で「文字幅」が変化するとは限らないので注意が必要です。
例えば、[㍉] という全角の非漢字文字は、 [ミ][リ] という全角カタカナ 2 文字に分解されます。
互換等価性による分解
正規化の種類 | かな文字の挙動 | 例 |
---|---|---|
分解 | 半角文字を全角文字にする。 (ラテン文字の場合は逆) |
[ コ ] => [ コ ] [ A ] => [ A ] |
なお、「互換等価性による合成」という言葉は Uicode 正規化の仕様には出てこないようですが、かな文字の全角から半角への変換はこれにあたると考えることもできるでしょう。
Golang の準標準ライブラリ
冒頭で触れたとおり、Golang の準標準ライブラリには Unicode Normalization Form 関連のパッケージが 2 つありますが、どちらもかな文字の扱いに関して問題があり、期待した結果を返してくれません。
golang.org/x/text/width の問題点
ひとつは golang.org/x/text/width パッケージで、これは互換等価性の分解と合成に近い働きをするものです。
(先に述べた通り互換等価性による合成という言葉は Unicode の仕様には出てきません)
要するに全角 (Full/Wide) と半角 (Half/Narrow) の変換をしてくれるものなのですが、このパッケージで 7 種類の「ゴ」を変換してみると可愛げのない挙動になります。
確認用のプログラムは以下のとおりです。
package main
import (
"fmt"
"golang.org/x/text/width"
"strings"
)
func hexs(s string) string {
var ss []string
for _, r := range []rune(s) {
e := fmt.Sprintf("%04X", r)
ss = append(ss, e)
}
switch len(ss) {
case 0:
return "<empty>"
case 1:
return "[" + ss[0] + "]"
default:
return "[" + strings.Join(ss, " ") + "]"
}
}
func main() {
s := "ゴコ゛コ\u3099ゴゴコ゛コ\u3099"
narrow := width.Narrow.String(s)
widen := width.Widen.String(s)
fold := width.Fold.String(s)
fmt.Printf("SRC :\t%q,\n\t%s\n", s, hexs(s))
fmt.Printf("NAR :\t%q,\n\t%s\n", narrow, hexs(narrow))
fmt.Printf("WIDE:\t%q,\n\t%s\n", widen, hexs(widen))
fmt.Printf("FOLD:\t%q,\n\t%s\n", fold, hexs(fold))
}
実行結果は以下のとおりです。
$ go run width_examples.go
SRC : "ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A 3099 30B4 30B3 FF9E 30B3 309B 30B3 3099]
NAR : "ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A FF9E 30B4 FF7A FF9E FF7A 309B FF7A FF9E]
WIDE: "ゴコ゛ゴゴゴコ゛ゴ",
[30B3 3099 30B3 309B 30B3 3099 30B4 30B3 3099 30B3 309B 30B3 3099]
FOLD: "ゴコ゛ゴゴゴコ゛ゴ",
[30B3 3099 30B3 309B 30B3 3099 30B4 30B3 3099 30B3 309B 30B3 3099]
結果を整理すると以下のようになります。
(具合の悪い箇所を赤くしています)
Source | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A 3099 |
ゴ 30B4 |
ゴ 30B3 FF9E |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
問題点 |
---|---|---|---|---|---|---|---|---|
Narrow | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A FF9E |
ゴ 30B4 |
ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A FF9E |
Wide VOM(309B) が Narrow にならない。 Wide Precomp(30B4) が Narrow にならない。 |
Widen | ゴ 30B3 3099 |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
ゴ 30B4 |
ゴ 30B3 3099 |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
3 つとも Precomp(30B4) になってほしい。 せめて Base + Combining (30B3+3099) に揃えてほしい。 |
Fold | ゴ 30B3 3099 |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
ゴ 30B4 |
ゴ 30B3 3099 |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
Fold は Latin を Narrow に、Kana を Wide にする Transformer。問題点は Widen と同様。 |
golang.org/x/text/unicode/norm の問題点
もうひとつは golang.org/x/text/unicode/norm で、4 種類の Unicode Normalization Form をサポートしています。
4 種類の Unicode 正規化形式
形式 | 説明 | かな文字の場合 |
---|---|---|
NFD | 正準等価性によって分解される。 | 濁点や半濁点が基底文字から分離する。Precomp => Base + Combining |
NFC | 正準等価性によって分解された後に、正準等価性によって合成される。 | 濁点や半濁点が基底文字から分離した後に再度合成される。 Precomp => Base + Combining, Base + Combining => Precomp |
NFKD | 互換等価性によって分解される。 | 半角カタカナが全角カタカナになる。 Narrow => Wide |
NFKC | 互換等価性によって分解された後に、正準等価性によって合成される。 | 半角カタカナが全角カタカナに変換された後に、基底文字と合成文字が合成される。 Narrow => Wide, Base + Combining => Precomp |
7 種類の「ゴ」を変換してみます。
package main
import (
"fmt"
"golang.org/x/text/unicode/norm"
"strings"
)
func hexs(s string) string {
var ss []string
for _, r := range []rune(s) {
e := fmt.Sprintf("%04X", r)
ss = append(ss, e)
}
switch len(ss) {
case 0:
return "<empty>"
case 1:
return "[" + ss[0] + "]"
default:
return "[" + strings.Join(ss, " ") + "]"
}
}
func main() {
s := "ゴコ゛コ\u3099ゴゴコ゛コ\u3099"
nfd := norm.NFD.String(s) // Canonical decomposition
nfkd := norm.NFKD.String(s) // Compatibility decomposition
nfc := norm.NFC.String(s) // Canonical decomposition -> Canonical composition
nfkc := norm.NFKC.String(s) // Compatibility decomposition -> Ccanonical composition
fmt.Printf("SRC :\t%q,\n\t%s\n", s, hexs(s))
fmt.Printf("NFD :\t%q,\n\t%s\n", nfd, hexs(nfd))
fmt.Printf("NFKD:\t%q,\n\t%s\n", nfkd, hexs(nfkd))
fmt.Printf("NFC :\t%q,\n\t%s\n", nfc, hexs(nfc))
fmt.Printf("NFKC:\t%q,\n\t%s\n", nfkc, hexs(nfkc))
}
実行結果は以下のとおりです。
$ go run norm_examples.go
SRC : "ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A 3099 30B4 30B3 FF9E 30B3 309B 30B3 3099]
NFD : "ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A 3099 30B3 3099 30B3 FF9E 30B3 309B 30B3 3099]
NFKD: "ゴコ ゙ゴゴゴコ ゙ゴ",
[30B3 3099 30B3 0020 3099 30B3 3099 30B3 3099 30B3 3099 30B3 0020 3099 30B3 3099]
NFC : "ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A 3099 30B4 30B3 FF9E 30B3 309B 30B4]
NFKC: "ゴコ ゙ゴゴゴコ ゙ゴ",
[30B4 30B3 0020 3099 30B4 30B4 30B4 30B3 0020 3099 30B4]
結果を整理すると以下のようになります。
Source | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A 3099 |
ゴ 30B4 |
ゴ 30B3 FF9E |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
問題点 |
---|---|---|---|---|---|---|---|---|
NFD | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A 3099 |
ゴ 30B3 3099 |
ゴ 30B3 FF9E |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
Combining ではない VOM が無視される。 |
NFC | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A 3099 |
ゴ 30B4 |
ゴ 30B3 FF9E |
コ゛ 30B3 309B |
ゴ 30B4 |
NFD と同様。 |
NFKD | ゴ 30B3 3099 |
コ ゙ 30B3 0020 3099 |
ゴ 30B3 3099 |
ゴ 30B3 3099 |
ゴ 30B3 3099 |
コ ゙ 30B3 0020 3099 |
ゴ 30B3 3099 |
全角の VOM が Whitespace + Combining になる。 |
NFKC | ゴ 30B4 |
コ ゙ 30B3 0020 3099 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
コ ゙ 30B3 0020 3099 |
ゴ 30B4 |
全角の VOM が Wthitespace + Combining になるため、再合成されない。 |
仕様通りに振舞っているのだとは思います。
でも、このパッケージをありがたいと感じている日本人は少ないのではないでしょうか。
どんなライブラリを作ったのか?
日本語文字列ユーティリティです。
ノーマライザは、日本語のロケールで良く使われる 426 文字(ASCII 互換のラテン文字と JIS 互換のひらがなカタカナなど)をサポートしており、文字列の縦書き関数などを同梱しています。
ダウンロード
ソースコードは GitHub に置いてあります。
go-gaga (Japanese language utility)
README
Golang の環境があれば、以下のコマンドでライブラリが使えるようになります。
$ go get github.com/y-bash/go-gaga
使い方
まず、正規化ルールをフラグで指定して Normalizer を生成します。
(エラー処理については後述します)
n, err := gaga.Norm(gaga.LatinToNarrow | gaga.KanaToWide)
あとは String() メソッドを呼ぶだけです。
s := n.String("変換したい文字列")
途中でフラグを変更することもできます。
(エラー処理については後述します)
err = n.SetFlag(gaga.LatinToWide)
s = n.String("変換したい文字列")
もう少し具体的なコードの例を示します。
以下のように文字種別ごとに半角全角の変換、濁点・半濁点の結合、分解、カタカナひらがなの変換、大文字小文字の変換が行えます。
package main
import (
"fmt"
"github.com/y-bash/go-gaga"
)
func main() {
s := "ゴコ゛コ\u3099ゴゴコ゛コ\u3099"
n, _ := gaga.Norm(gaga.ComposeVom) // 濁点と半濁点を適切に結合する
fmt.Println(n.String(s)) // => ゴゴゴゴゴゴゴ
n, _ = gaga.Norm(gaga.KanaToNarrow) // ひらがなとカタカナを半角にする
fmt.Println(n.String(s)) // => ゴゴゴゴゴゴゴ
n, _ = gaga.Norm(gaga.KanaToWide) // カタカナを全角にする
fmt.Println(n.String(s)) // => ゴゴゴゴゴゴゴ
n, _ = gaga.Norm(gaga.KanaToHiragana) // カタカナをひらがなにする
fmt.Println(n.String(s)) // => ごごごごごごご
s = "abcアイウ"
n, _ = gaga.Norm(
gaga.LatinToNarrow | // ラテン文字を半角に、
gaga.AlphaToUpper | // アルファベットを大文字に、
gaga.KanaToHiragana) // カタカナをひらがなにする
fmt.Println(n.String(s)) // => ABCあいう
}
gaga で width や norm と同様のプログラムを書いてみます。
package main
import (
"fmt"
"github.com/y-bash/go-gaga"
"strings"
)
func hexs(s string) string {
var ss []string
for _, r := range []rune(s) {
e := fmt.Sprintf("%04X", r)
ss = append(ss, e)
}
switch len(ss) {
case 0:
return "<empty>"
case 1:
return "[" + ss[0] + "]"
default:
return "[" + strings.Join(ss, " ") + "]"
}
}
func main() {
s := "ゴコ゛コ\u3099ゴゴコ゛コ\u3099"
n, _ := gaga.Norm(gaga.ComposeVom)
co := n.String(s)
n.SetFlag(gaga.DecomposeVom)
de:= n.String(s)
n.SetFlag(gaga.KanaToNarrow)
na:= n.String(s)
n.SetFlag(gaga.KanaToWide)
wi:= n.String(s)
n.SetFlag(gaga.KanaToHiragana)
hi := n.String(s)
n.SetFlag(gaga.KatakanaToHiragana | gaga.DecomposeVom)
hd := n.String(s)
fmt.Printf("SRC :%q,\n\t%s\n", s, hexs(s))
fmt.Printf("ComposeVom :%q,\n\t%s\n", co, hexs(co))
fmt.Printf("DecomposeVom :%q,\n\t%s\n", de, hexs(de))
fmt.Printf("KanaToNarrow :%q,\n\t%s\n", na, hexs(na))
fmt.Printf("KanaToWide :%q,\n\t%s\n", wi, hexs(wi))
fmt.Printf("KanaToHiragana :%q,\n\t%s\n", hi, hexs(hi))
fmt.Printf("Hiragana&DecVom:%q,\n\t%s\n", hd, hexs(hd))
}
結果は以下のとおりです。
$ go run gaga_examples.go
SRC :"ゴコ゛ゴゴゴコ゛ゴ",
[FF7A FF9E FF7A 309B FF7A 3099 30B4 30B3 FF9E 30B3 309B 30B3 3099]
ComposeVom :"ゴゴゴゴゴゴゴ",
[FF7A FF9E FF7A FF9E FF7A FF9E 30B4 30B4 30B4 30B4]
DecomposeVom :"ゴゴゴゴゴゴゴ",
[FF7A 3099 FF7A 3099 FF7A 3099 30B3 3099 30B3 3099 30B3 3099 30B3 3099]
KanaToNarrow :"ゴゴゴゴゴゴゴ",
[FF7A FF9E FF7A FF9E FF7A FF9E FF7A FF9E FF7A FF9E FF7A FF9E FF7A FF9E]
KanaToWide :"ゴゴゴゴゴゴゴ",
[30B4 30B4 30B4 30B4 30B4 30B4 30B4]
KanaToHiragana :"ごごごごごごご",
[3054 3054 3054 3054 3054 3054 3054]
Hiragana&DecVom:"ごごごごごごご",
[3053 3099 3053 3099 3053 3099 3053 3099 3053 3099 3053 3099 3053 3099]
結果を整理すると以下のようになります。
Source | ゴ FF7A FF9E |
コ゛ FF7A 309B |
ゴ FF7A 3099 |
ゴ 30B4 |
ゴ 30B3 FF9E |
コ゛ 30B3 309B |
ゴ 30B3 3099 |
---|---|---|---|---|---|---|---|
ComposeVom | ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
DecomposeVom | ゴ FF7A 3099 |
ゴ FF7A 3099 |
ゴ FF7A 3099 |
ゴ 30B3 3099 |
ゴ 30B3 3099 |
ゴ 30B3 3099 |
ゴ 30B3 3099 |
KanaToNarrow | ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
ゴ FF7A FF9E |
KanaToWide | ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
ゴ 30B4 |
KanaToHiragana | ご 3054 |
ご 3054 |
ご 3054 |
ご 3054 |
ご 3054 |
ご 3054 |
ご 3054 |
KatakanaToHiragana | DecomposeVom |
ご 3053 3099 |
ご 3053 3099 |
ご 3053 3099 |
ご 3053 3099 |
ご 3053 3099 |
ご 3053 3099 |
ご 3053 3099 |
エラーハンドリングについて
上記のコードでは見やすさのために省略していましたが、実際に使う際はエラーを適切にハンドリングする必要があります。gaga.Norm() も、gaga.Normalizer.SetFlag() も、存在しない値や排他的なフラグの組み合わせ(例えば KanaToNarrow | KanaToWide など)が指定されると error を返します。
以下にエラーハンドリングの例を記しておきます。
package main
import (
"fmt"
"github.com/y-bash/go-gaga"
"log"
)
func main() {
n, err := gaga.Norm(gaga.LatinToWide | gaga.AlphaToUpper)
if err != nil {
log.Fatal(err)
}
fmt.Println(n.String("aaa"))
fmt.Println(n.String("bbb"))
fmt.Println(n.String("ccc"))
err = n.SetFlag(gaga.LatinToNarrow | gaga.SymbolToWide)
if err != nil {
log.Fatal(err)
}
fmt.Println(n.String("aaa"))
fmt.Println(n.String("bbb"))
fmt.Println(n.String("ccc"))
}
$ go run gaga_error.go
AAA
BBB
CCC
2020/09/20 08:57:21 invalid normalization flag: (AlphaToNarrow | DigitToNarrow | SymbolToNarrow | SymbolToWide), invalid combination: (SymbolToNarrow | SymbolToWide)
exit status 1
コマンドラインツール
go build や go install でライブラリと同じ機能を持つコマンドラインツールをビルドできます。
Linux と Windows で動作確認しています。
norm コマンド README
フラグの種類
変換ルールを指示するための 20 個のフラグ定数(単独フラグ)が用意されています。
ノーマライザを生成する際にこれを指定して使うのですが、その際、フラグをビット OR 演算子で組み合わせて指定することができます。
また、複数のフラグを組み合わせた定数(コンビネーションフラグ)が 8 個用意されているので、通常はこちらを使う方が便利でしょう。
コンビネーションフラグ (8個)
フラグ | 意味 | 同等の組み合わせ |
---|---|---|
LatinToNarrow | アルファベット、ラテン数字、ラテンシンボルを半角にする。 【例】 "A1?" => "A1?" |
AlphaToNarrow | DigitToNarrow | SymbolToNarrow |
LatinToWide | アルファベット、ラテン数字、ラテンシンボルを全角にする。 【例】 "A1?" => "A1?" |
AlphaToWide | DigitToWide | SymbolToWide |
KanaToNarrow | ひらがな、カタカナ、仮名シンボルを半角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を半角にする。 【例】 "あイ、が゛" => "アイ、ガ゙" |
HiraganaToNarrow | KatakanaToNarrow | KanaSymbolToNarrow | IsolatedVomToNarrow | ComposeVom |
KanaToWide | カタカナ、仮名シンボルを全角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を全角にする。 【例】 "ア、ガ゙" => "ア、ガ゛" |
KatakanaToWide | KanaSymbolToWide | IsolatedVomToWide | ComposeVom |
KanaToWideKatakana | ひらがなを全角カタカナにする。半角カタカナを全角カタカナにする。仮名シンボルを全角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を全角にする。 【例】 "あイ、ガ゙" => "アイ、ガ゛" |
KatakanaToWide | HiraganaToKatakana | KanaSymbolToWide | IsolatedVomToWide | ComposeVom |
KanaToNarrowKatakana | ひらがなを半角カタカナにする。全角カタカナを半角カタカナにする。仮名シンボルを半角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を半角にする。 【例】 "あイ、が゛" => "アイ、ガ゙" |
KatakanaToNarrow | HiraganaToNarrow | KanaSymbolToNarrow | IsolatedVomToNarrow | ComposeVom |
KanaToHiragana | 全角カタカナと半角カタカナをひらがなにする。仮名シンボルを全角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を全角にする。 【例】 "アイ、ガ゛" => "あい、が゛" |
KatakanaToHiragana | KanaSymbolToWide | IsolatedVomToWide | ComposeVom |
Fold | 全角アルファベット、数字、シンボルを半角にする。半角カタカナを全角カタカナにする。半角仮名シンボルを全角にする。濁点および半濁点を従来の方法で結合する。独立した濁点半濁点を全角にする。 【例】 "A1?ア、ガ゙" => "A1?ア、ガ゛" |
LatinToNarrow | KanaToWide |
単独フラグ (20個)
フラグ | 意味 |
---|---|
AlphaToNarrow | 全角アルファベットを半角にする。 【例】 [A]=>[A] |
AlphaToWide | 半角アルファベットを全角にする。 【例】 [A]=>[A] |
AlphaToUpper | 半角アルファベットと全角アルファベットを大文字にする。 【例】 [a]=>[A], [a]=>[A] |
AlphaToLower | 半角アルファベットと全角アルファベットを小文字にする。 【例】 [A] => [a], [A] => [a] |
DigitToNarrow | 全角ラテン数字を半角にする。 【例】 [1]=>[1] |
DigitToWide | 半角ラテン数字を全角にする。 【例】 [1]=>[1] |
SymbolToNarrow | 全角ラテン・シンボルを半角にする。 【例】 [?]=>[?] |
SymbolToWide | 半角ラテン・シンボルを全角にする。 【例】 [?]=>[?] |
HiraganaToNarrow | ひらがなを半角カタカナにする。 【例】 [あ]=>[ア] |
HiraganaToKatakana | ひらがなを全角カタカナにする。 【例】 [あ]=>[ア] |
KatakanaToNarrow | 全角カタカナを半角にする。 【例】 [ア]=>[ア] |
KatakanaToWide | 半角カタカナを全角にする。 【例】 [ア]=>[ア] |
KatakanaToHiragana | 半角カタカナと全角カタカナをひらがなにする。 【例】 [ア] => [あ] [ア] => [あ] |
KanaSymbolToNarrow | 全角仮名シンボルを半角にする。 【例】 [、]=>[、] |
KanaSymbolToWide | 半角仮名シンボルを全角にする。 【例】 [、]=>[、] |
ComposeVom | 濁点と半濁点を従来の方法で結合する。 【例】 [か][゛]=>[が] [か][U+3099] => [が] [か][゙]=>[が] [カ][゛]=>[カ][゙] [カ][゙]=>[カ][゙] [カ][U+3099]=>[カ][゙] [は][゜]=>[ぱ] [ヰ][゛]=>[ヸ] Pre-composed character を持たないひらがなカタカナに続く濁点と半濁点は、先行する文字と同じ幅に変換される。 [あ][゙]=>[あ][゛] [あ][U+3099]=>[あ][゛] [ア][゛]=>[ア][゙] [ア][U+3099]=>[ア][゙] [ゐ][゛]=>[ゐ][゛] Pre-composed character に続く濁点と半濁点はこのフラグでは変換されない。 【例】[が][゛]=>[が][゛] [が][U+3099]=>[が][U+3099] [が][゙]=>[が][゙] ひらがなカタカナ以外の文字に続く濁点と半濁点はこのフラグでは変換されない。 【例】 [日][゛]=>[日][゛] [日][U+3099]=>[日][U+3099] [日][゙]=>[日][゙] |
DecomposeVom | 濁点と半濁点を Unicode Normalization Form の正準等価による分解に似た方法で分解する。 【例】 [が]=>[か][U+3099] [か][゛]=>[か][U+3099] [か][゙]=>[か][U+3099] [カ][゛]=>[カ][U+3099] [カ][゙]=>[カ][U+3099] [は][゜]=>[は][U+309A] [あ][゛]=>[あ][U+3099] Pre-composed character に続く濁点と半濁点はこのフラグでは変換されない。 ひらがなカタカナ以外の文字に続く濁点と半濁点はこのフラグでは変換されない。 |
IsolatedVomToNarrow | Base character に接続されない独立した濁点と半濁点を半角にする。 【例】 [゛]=>[゙] [U+3099]=>[゙] [゜]=>[゚] [U+309A]=>[゚] |
IsolatedVomToWide | Base character に接続されない独立した濁点と半濁点を全角にする。 【例】 [゙]=>[゛] [U+3099]=>[゛] [゚]=>[゜] [U+309A]=>[゜] |
IsolatedVomToNonspace | Base character に接続されない独立した濁点と半濁点を Non-space (Combining character) にする。 【例】 [゛]=>[U+3099] [゙]=>[U+3099] [゜]=>[U+309A] [゚]=>[U+309A] |
どのように実装したのか?
The Unicode Consortium が提供する UCD in XML (Unicode Character Database in XML) を元に Golang 用のテーブルを生成しています。
ジェネレータのコード
ジェネレータが生成したテーブル (unichar_tables.go)
コード生成の大まかな流れは以下のとおりです。
コード生成シーケンス
No. | プロセス | 補足 |
---|---|---|
1. | zip 形式ファイルのダウンロード | |
2. | zip 解凍、XML ファイル (UCD) の取り出し | |
3. | XML ファイルのパース | |
4. | パースした XML を CSV として出力 | 確認用 Utility (ソースコード生成とは別のコマンド) |
5. | UCD に足りない情報の付与 | 追加した情報 - ひらがな-カタカナのリレーション、 - 全角小書き文字-半角並字のリレーションなど |
6. | 文字間の双方向リンクの作成 | UCD のひらがなカタカナ情報には片方向のリンクしかない。 - Narrow->Wide(ア->ア など) - Precomp->Base,Combining (ガ->カ,◌゙ など) ※ラテン文字の Uppercase と Lowercase については双方向のリンク情報がある |
7. | 拡張 UCD (5, 6 を施したもの)を CSV 出力 | 確認用 Utility (ソースコード生成とは別のコマンド) 多言語ライブラリへの移植用としての活用も想定 (Rust, TypeScript/JavaScript, etc...) |
8. | 拡張 UCD を Golang のテーブルとして出力 | with go fmt |
なお、コード生成については以下の情報を参考にさせていただきました。
- yaegashi さん の記事 - go generate のベストプラクティス
- mattn さん のライブラリ - go-runewidth
yaegashi さんの記事は、ジェネレータを含むプロジェクトのリポジトリ構成をどうすべきかという点について参考にさせていただきました。
mattn さんの go-runewidth からも多くの事を学ばせていただきました。中でも生成したテーブル構造のチェックサムをテストするアイデアを真似させていただき、これがとても気に入ってます。これを行うことで、万一、元ネタ(ダウンロードデータ)の内容が変更されたり、ジェネレータをリファクタリングした際にうっかり生成コードを壊してしまうようなことがあってもすぐ気づくことができます。
また、GaGa に同梱した 縦書きコマンド vert の中で go-runewidth を使わせていただいています。
お二人ともありがとうございました。
パフォーマンスは良いのか?
パフォーマンスは悪くないと思います。
というか、VOM の結合と分解をしているところ以外は、アルゴリズム的にほぼ何もしていません(笑)
Unicode のブロックごとに 4 つのテーブル (配列) があり(連続するブロックは 1 つにまとめています)、変換する文字がこれのどれにあたるのかを線形検索しているところの平均計算量が O(2)、
テーブルが決まってからは、変換する文字のコードポイント(rune の値)からオフセット値を計算、それを配列のインデックスにして要素を取り出しているところの計算量が O(1) です。
ベンチマークのコードと結果は以下のとおりです。
const normSTR = "Aa# Aa#あア。ア。”゙漢字ガギグゲゴパピプペポ"
func BenchmarkString(b *testing.B) {
b.ResetTimer()
n, _ := Norm(LatinToNarrow | KanaToWide)
for i := 0; i < b.N; i++ {
n.String(normSTR)
}
b.StopTimer()
}
func BenchmarkNormNFKD(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
norm.NFKD.String(normSTR)
}
b.StopTimer()
}
func BenchmarkNormNFKC(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
norm.NFKC.String(normSTR)
}
b.StopTimer()
}
func BenchmarkWidthNarrow(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
width.Narrow.String(normSTR)
}
b.StopTimer()
}
func BenchmarkWidthWiden(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
width.Widen.String(normSTR)
}
b.StopTimer()
}
func BenchmarkWidthFold(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
width.Fold.String(normSTR)
}
b.StopTimer()
}
$ make bench
go test -v -run "Benchmark" -bench . -benchmem -o ./output/bench.bin -cpuprofile=./output/cpu.prof -memprofile=./output/mem.prof
goos: linux
goarch: amd64
pkg: github.com/y-bash/go-gaga
BenchmarkString
BenchmarkString-2 713604 1683 ns/op 224 B/op 2 allocs/op
BenchmarkNormNFKD
BenchmarkNormNFKD-2 189483 6348 ns/op 784 B/op 3 allocs/op
BenchmarkNormNFKC
BenchmarkNormNFKC-2 165166 7101 ns/op 752 B/op 3 allocs/op
BenchmarkWidthNarrow
BenchmarkWidthNarrow-2 1395560 892 ns/op 368 B/op 3 allocs/op
BenchmarkWidthWiden
BenchmarkWidthWiden-2 1392997 854 ns/op 384 B/op 3 allocs/op
BenchmarkWidthFold
BenchmarkWidthFold-2 1452519 822 ns/op 368 B/op 3 allocs/op
上記結果を gaga を 100 として比較すると以下のようになります。
パッケージ | 処理時間 | メモリ使用量 | アロケーション回数 |
---|---|---|---|
gaga | 100 | 100 | 100 |
norm.NFKD | 377 | 350 | 150 |
norm.NFKC | 422 | 336 | 150 |
width.Narrow | 53 | 164 | 150 |
width.Widen | 51 | 171 | 150 |
width.Fold | 49 | 164 | 150 |
norm パッケージの 3 〜 4 倍の速度が出ているので悪くないと思います。
width は速いですね。VOMの結合と分解をしていないからですかね …
GaGa がサポートする 462文字
ライブラリがサポートする文字の一覧表を挙げておきます。
一覧表を展開する
Block
Name
Age
Codepoint
Glyph
ASCII
SPACE
1.1
U+0020
ASCII
EXCLAMATION MARK
1.1
U+0021
!
ASCII
QUOTATION MARK
1.1
U+0022
"
ASCII
NUMBER SIGN
1.1
U+0023
#
ASCII
DOLLAR SIGN
1.1
U+0024
$
ASCII
PERCENT SIGN
1.1
U+0025
%
ASCII
AMPERSAND
1.1
U+0026
&
ASCII
APOSTROPHE
1.1
U+0027
'
ASCII
LEFT PARENTHESIS
1.1
U+0028
(
ASCII
RIGHT PARENTHESIS
1.1
U+0029
)
ASCII
ASTERISK
1.1
U+002A
*
ASCII
PLUS SIGN
1.1
U+002B
+
ASCII
COMMA
1.1
U+002C
,
ASCII
HYPHEN-MINUS
1.1
U+002D
-
ASCII
FULL STOP
1.1
U+002E
.
ASCII
SOLIDUS
1.1
U+002F
/
ASCII
DIGIT ZERO
1.1
U+0030
0
ASCII
DIGIT ONE
1.1
U+0031
1
ASCII
DIGIT TWO
1.1
U+0032
2
ASCII
DIGIT THREE
1.1
U+0033
3
ASCII
DIGIT FOUR
1.1
U+0034
4
ASCII
DIGIT FIVE
1.1
U+0035
5
ASCII
DIGIT SIX
1.1
U+0036
6
ASCII
DIGIT SEVEN
1.1
U+0037
7
ASCII
DIGIT EIGHT
1.1
U+0038
8
ASCII
DIGIT NINE
1.1
U+0039
9
ASCII
COLON
1.1
U+003A
:
ASCII
SEMICOLON
1.1
U+003B
;
ASCII
LESS-THAN SIGN
1.1
U+003C
<
ASCII
EQUALS SIGN
1.1
U+003D
=
ASCII
GREATER-THAN SIGN
1.1
U+003E
>
ASCII
QUESTION MARK
1.1
U+003F
?
ASCII
COMMERCIAL AT
1.1
U+0040
@
ASCII
LATIN CAPITAL LETTER A
1.1
U+0041
A
ASCII
LATIN CAPITAL LETTER B
1.1
U+0042
B
ASCII
LATIN CAPITAL LETTER C
1.1
U+0043
C
ASCII
LATIN CAPITAL LETTER D
1.1
U+0044
D
ASCII
LATIN CAPITAL LETTER E
1.1
U+0045
E
ASCII
LATIN CAPITAL LETTER F
1.1
U+0046
F
ASCII
LATIN CAPITAL LETTER G
1.1
U+0047
G
ASCII
LATIN CAPITAL LETTER H
1.1
U+0048
H
ASCII
LATIN CAPITAL LETTER I
1.1
U+0049
I
ASCII
LATIN CAPITAL LETTER J
1.1
U+004A
J
ASCII
LATIN CAPITAL LETTER K
1.1
U+004B
K
ASCII
LATIN CAPITAL LETTER L
1.1
U+004C
L
ASCII
LATIN CAPITAL LETTER M
1.1
U+004D
M
ASCII
LATIN CAPITAL LETTER N
1.1
U+004E
N
ASCII
LATIN CAPITAL LETTER O
1.1
U+004F
O
ASCII
LATIN CAPITAL LETTER P
1.1
U+0050
P
ASCII
LATIN CAPITAL LETTER Q
1.1
U+0051
Q
ASCII
LATIN CAPITAL LETTER R
1.1
U+0052
R
ASCII
LATIN CAPITAL LETTER S
1.1
U+0053
S
ASCII
LATIN CAPITAL LETTER T
1.1
U+0054
T
ASCII
LATIN CAPITAL LETTER U
1.1
U+0055
U
ASCII
LATIN CAPITAL LETTER V
1.1
U+0056
V
ASCII
LATIN CAPITAL LETTER W
1.1
U+0057
W
ASCII
LATIN CAPITAL LETTER X
1.1
U+0058
X
ASCII
LATIN CAPITAL LETTER Y
1.1
U+0059
Y
ASCII
LATIN CAPITAL LETTER Z
1.1
U+005A
Z
ASCII
LEFT SQUARE BRACKET
1.1
U+005B
[
ASCII
REVERSE SOLIDUS
1.1
U+005C
\
ASCII
RIGHT SQUARE BRACKET
1.1
U+005D
]
ASCII
CIRCUMFLEX ACCENT
1.1
U+005E
^
ASCII
LOW LINE
1.1
U+005F
_
ASCII
GRAVE ACCENT
1.1
U+0060
`
ASCII
LATIN SMALL LETTER A
1.1
U+0061
a
ASCII
LATIN SMALL LETTER B
1.1
U+0062
b
ASCII
LATIN SMALL LETTER C
1.1
U+0063
c
ASCII
LATIN SMALL LETTER D
1.1
U+0064
d
ASCII
LATIN SMALL LETTER E
1.1
U+0065
e
ASCII
LATIN SMALL LETTER F
1.1
U+0066
f
ASCII
LATIN SMALL LETTER G
1.1
U+0067
g
ASCII
LATIN SMALL LETTER H
1.1
U+0068
h
ASCII
LATIN SMALL LETTER I
1.1
U+0069
i
ASCII
LATIN SMALL LETTER J
1.1
U+006A
j
ASCII
LATIN SMALL LETTER K
1.1
U+006B
k
ASCII
LATIN SMALL LETTER L
1.1
U+006C
l
ASCII
LATIN SMALL LETTER M
1.1
U+006D
m
ASCII
LATIN SMALL LETTER N
1.1
U+006E
n
ASCII
LATIN SMALL LETTER O
1.1
U+006F
o
ASCII
LATIN SMALL LETTER P
1.1
U+0070
p
ASCII
LATIN SMALL LETTER Q
1.1
U+0071
q
ASCII
LATIN SMALL LETTER R
1.1
U+0072
r
ASCII
LATIN SMALL LETTER S
1.1
U+0073
s
ASCII
LATIN SMALL LETTER T
1.1
U+0074
t
ASCII
LATIN SMALL LETTER U
1.1
U+0075
u
ASCII
LATIN SMALL LETTER V
1.1
U+0076
v
ASCII
LATIN SMALL LETTER W
1.1
U+0077
w
ASCII
LATIN SMALL LETTER X
1.1
U+0078
x
ASCII
LATIN SMALL LETTER Y
1.1
U+0079
y
ASCII
LATIN SMALL LETTER Z
1.1
U+007A
z
ASCII
LEFT CURLY BRACKET
1.1
U+007B
{
ASCII
VERTICAL LINE
1.1
U+007C
ASCII
RIGHT CURLY BRACKET
1.1
U+007D
}
ASCII
TILDE
1.1
U+007E
~
CJK_Symbols
IDEOGRAPHIC SPACE
1.1
U+3000
CJK_Symbols
IDEOGRAPHIC COMMA
1.1
U+3001
、
CJK_Symbols
IDEOGRAPHIC FULL STOP
1.1
U+3002
。
CJK_Symbols
LEFT CORNER BRACKET
1.1
U+300C
「
CJK_Symbols
RIGHT CORNER BRACKET
1.1
U+300D
」
Hiragana
HIRAGANA LETTER SMALL A
1.1
U+3041
ぁ
Hiragana
HIRAGANA LETTER A
1.1
U+3042
あ
Hiragana
HIRAGANA LETTER SMALL I
1.1
U+3043
ぃ
Hiragana
HIRAGANA LETTER I
1.1
U+3044
い
Hiragana
HIRAGANA LETTER SMALL U
1.1
U+3045
ぅ
Hiragana
HIRAGANA LETTER U
1.1
U+3046
う
Hiragana
HIRAGANA LETTER SMALL E
1.1
U+3047
ぇ
Hiragana
HIRAGANA LETTER E
1.1
U+3048
え
Hiragana
HIRAGANA LETTER SMALL O
1.1
U+3049
ぉ
Hiragana
HIRAGANA LETTER O
1.1
U+304A
お
Hiragana
HIRAGANA LETTER KA
1.1
U+304B
か
Hiragana
HIRAGANA LETTER GA
1.1
U+304C
が
Hiragana
HIRAGANA LETTER KI
1.1
U+304D
き
Hiragana
HIRAGANA LETTER GI
1.1
U+304E
ぎ
Hiragana
HIRAGANA LETTER KU
1.1
U+304F
く
Hiragana
HIRAGANA LETTER GU
1.1
U+3050
ぐ
Hiragana
HIRAGANA LETTER KE
1.1
U+3051
け
Hiragana
HIRAGANA LETTER GE
1.1
U+3052
げ
Hiragana
HIRAGANA LETTER KO
1.1
U+3053
こ
Hiragana
HIRAGANA LETTER GO
1.1
U+3054
ご
Hiragana
HIRAGANA LETTER SA
1.1
U+3055
さ
Hiragana
HIRAGANA LETTER ZA
1.1
U+3056
ざ
Hiragana
HIRAGANA LETTER SI
1.1
U+3057
し
Hiragana
HIRAGANA LETTER ZI
1.1
U+3058
じ
Hiragana
HIRAGANA LETTER SU
1.1
U+3059
す
Hiragana
HIRAGANA LETTER ZU
1.1
U+305A
ず
Hiragana
HIRAGANA LETTER SE
1.1
U+305B
せ
Hiragana
HIRAGANA LETTER ZE
1.1
U+305C
ぜ
Hiragana
HIRAGANA LETTER SO
1.1
U+305D
そ
Hiragana
HIRAGANA LETTER ZO
1.1
U+305E
ぞ
Hiragana
HIRAGANA LETTER TA
1.1
U+305F
た
Hiragana
HIRAGANA LETTER DA
1.1
U+3060
だ
Hiragana
HIRAGANA LETTER TI
1.1
U+3061
ち
Hiragana
HIRAGANA LETTER DI
1.1
U+3062
ぢ
Hiragana
HIRAGANA LETTER SMALL TU
1.1
U+3063
っ
Hiragana
HIRAGANA LETTER TU
1.1
U+3064
つ
Hiragana
HIRAGANA LETTER DU
1.1
U+3065
づ
Hiragana
HIRAGANA LETTER TE
1.1
U+3066
て
Hiragana
HIRAGANA LETTER DE
1.1
U+3067
で
Hiragana
HIRAGANA LETTER TO
1.1
U+3068
と
Hiragana
HIRAGANA LETTER DO
1.1
U+3069
ど
Hiragana
HIRAGANA LETTER NA
1.1
U+306A
な
Hiragana
HIRAGANA LETTER NI
1.1
U+306B
に
Hiragana
HIRAGANA LETTER NU
1.1
U+306C
ぬ
Hiragana
HIRAGANA LETTER NE
1.1
U+306D
ね
Hiragana
HIRAGANA LETTER NO
1.1
U+306E
の
Hiragana
HIRAGANA LETTER HA
1.1
U+306F
は
Hiragana
HIRAGANA LETTER BA
1.1
U+3070
ば
Hiragana
HIRAGANA LETTER PA
1.1
U+3071
ぱ
Hiragana
HIRAGANA LETTER HI
1.1
U+3072
ひ
Hiragana
HIRAGANA LETTER BI
1.1
U+3073
び
Hiragana
HIRAGANA LETTER PI
1.1
U+3074
ぴ
Hiragana
HIRAGANA LETTER HU
1.1
U+3075
ふ
Hiragana
HIRAGANA LETTER BU
1.1
U+3076
ぶ
Hiragana
HIRAGANA LETTER PU
1.1
U+3077
ぷ
Hiragana
HIRAGANA LETTER HE
1.1
U+3078
へ
Hiragana
HIRAGANA LETTER BE
1.1
U+3079
べ
Hiragana
HIRAGANA LETTER PE
1.1
U+307A
ぺ
Hiragana
HIRAGANA LETTER HO
1.1
U+307B
ほ
Hiragana
HIRAGANA LETTER BO
1.1
U+307C
ぼ
Hiragana
HIRAGANA LETTER PO
1.1
U+307D
ぽ
Hiragana
HIRAGANA LETTER MA
1.1
U+307E
ま
Hiragana
HIRAGANA LETTER MI
1.1
U+307F
み
Hiragana
HIRAGANA LETTER MU
1.1
U+3080
む
Hiragana
HIRAGANA LETTER ME
1.1
U+3081
め
Hiragana
HIRAGANA LETTER MO
1.1
U+3082
も
Hiragana
HIRAGANA LETTER SMALL YA
1.1
U+3083
ゃ
Hiragana
HIRAGANA LETTER YA
1.1
U+3084
や
Hiragana
HIRAGANA LETTER SMALL YU
1.1
U+3085
ゅ
Hiragana
HIRAGANA LETTER YU
1.1
U+3086
ゆ
Hiragana
HIRAGANA LETTER SMALL YO
1.1
U+3087
ょ
Hiragana
HIRAGANA LETTER YO
1.1
U+3088
よ
Hiragana
HIRAGANA LETTER RA
1.1
U+3089
ら
Hiragana
HIRAGANA LETTER RI
1.1
U+308A
り
Hiragana
HIRAGANA LETTER RU
1.1
U+308B
る
Hiragana
HIRAGANA LETTER RE
1.1
U+308C
れ
Hiragana
HIRAGANA LETTER RO
1.1
U+308D
ろ
Hiragana
HIRAGANA LETTER SMALL WA
1.1
U+308E
ゎ
Hiragana
HIRAGANA LETTER WA
1.1
U+308F
わ
Hiragana
HIRAGANA LETTER WI
1.1
U+3090
ゐ
Hiragana
HIRAGANA LETTER WE
1.1
U+3091
ゑ
Hiragana
HIRAGANA LETTER WO
1.1
U+3092
を
Hiragana
HIRAGANA LETTER N
1.1
U+3093
ん
Hiragana
HIRAGANA LETTER VU
1.1
U+3094
ゔ
Hiragana
HIRAGANA LETTER SMALL KA
3.2
U+3095
ゕ
Hiragana
HIRAGANA LETTER SMALL KE
3.2
U+3096
ゖ
Hiragana
COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
1.1
U+3099
゙
Hiragana
COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
1.1
U+309A
゚
Hiragana
KATAKANA-HIRAGANA VOICED SOUND MARK
1.1
U+309B
゛
Hiragana
KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
1.1
U+309C
゜
Hiragana
HIRAGANA ITERATION MARK
1.1
U+309D
ゝ
Hiragana
HIRAGANA VOICED ITERATION MARK
1.1
U+309E
ゞ
Hiragana
HIRAGANA DIGRAPH YORI
3.2
U+309F
ゟ
Katakana
KATAKANA-HIRAGANA DOUBLE HYPHEN
3.2
U+30A0
゠
Katakana
KATAKANA LETTER SMALL A
1.1
U+30A1
ァ
Katakana
KATAKANA LETTER A
1.1
U+30A2
ア
Katakana
KATAKANA LETTER SMALL I
1.1
U+30A3
ィ
Katakana
KATAKANA LETTER I
1.1
U+30A4
イ
Katakana
KATAKANA LETTER SMALL U
1.1
U+30A5
ゥ
Katakana
KATAKANA LETTER U
1.1
U+30A6
ウ
Katakana
KATAKANA LETTER SMALL E
1.1
U+30A7
ェ
Katakana
KATAKANA LETTER E
1.1
U+30A8
エ
Katakana
KATAKANA LETTER SMALL O
1.1
U+30A9
ォ
Katakana
KATAKANA LETTER O
1.1
U+30AA
オ
Katakana
KATAKANA LETTER KA
1.1
U+30AB
カ
Katakana
KATAKANA LETTER GA
1.1
U+30AC
ガ
Katakana
KATAKANA LETTER KI
1.1
U+30AD
キ
Katakana
KATAKANA LETTER GI
1.1
U+30AE
ギ
Katakana
KATAKANA LETTER KU
1.1
U+30AF
ク
Katakana
KATAKANA LETTER GU
1.1
U+30B0
グ
Katakana
KATAKANA LETTER KE
1.1
U+30B1
ケ
Katakana
KATAKANA LETTER GE
1.1
U+30B2
ゲ
Katakana
KATAKANA LETTER KO
1.1
U+30B3
コ
Katakana
KATAKANA LETTER GO
1.1
U+30B4
ゴ
Katakana
KATAKANA LETTER SA
1.1
U+30B5
サ
Katakana
KATAKANA LETTER ZA
1.1
U+30B6
ザ
Katakana
KATAKANA LETTER SI
1.1
U+30B7
シ
Katakana
KATAKANA LETTER ZI
1.1
U+30B8
ジ
Katakana
KATAKANA LETTER SU
1.1
U+30B9
ス
Katakana
KATAKANA LETTER ZU
1.1
U+30BA
ズ
Katakana
KATAKANA LETTER SE
1.1
U+30BB
セ
Katakana
KATAKANA LETTER ZE
1.1
U+30BC
ゼ
Katakana
KATAKANA LETTER SO
1.1
U+30BD
ソ
Katakana
KATAKANA LETTER ZO
1.1
U+30BE
ゾ
Katakana
KATAKANA LETTER TA
1.1
U+30BF
タ
Katakana
KATAKANA LETTER DA
1.1
U+30C0
ダ
Katakana
KATAKANA LETTER TI
1.1
U+30C1
チ
Katakana
KATAKANA LETTER DI
1.1
U+30C2
ヂ
Katakana
KATAKANA LETTER SMALL TU
1.1
U+30C3
ッ
Katakana
KATAKANA LETTER TU
1.1
U+30C4
ツ
Katakana
KATAKANA LETTER DU
1.1
U+30C5
ヅ
Katakana
KATAKANA LETTER TE
1.1
U+30C6
テ
Katakana
KATAKANA LETTER DE
1.1
U+30C7
デ
Katakana
KATAKANA LETTER TO
1.1
U+30C8
ト
Katakana
KATAKANA LETTER DO
1.1
U+30C9
ド
Katakana
KATAKANA LETTER NA
1.1
U+30CA
ナ
Katakana
KATAKANA LETTER NI
1.1
U+30CB
ニ
Katakana
KATAKANA LETTER NU
1.1
U+30CC
ヌ
Katakana
KATAKANA LETTER NE
1.1
U+30CD
ネ
Katakana
KATAKANA LETTER NO
1.1
U+30CE
ノ
Katakana
KATAKANA LETTER HA
1.1
U+30CF
ハ
Katakana
KATAKANA LETTER BA
1.1
U+30D0
バ
Katakana
KATAKANA LETTER PA
1.1
U+30D1
パ
Katakana
KATAKANA LETTER HI
1.1
U+30D2
ヒ
Katakana
KATAKANA LETTER BI
1.1
U+30D3
ビ
Katakana
KATAKANA LETTER PI
1.1
U+30D4
ピ
Katakana
KATAKANA LETTER HU
1.1
U+30D5
フ
Katakana
KATAKANA LETTER BU
1.1
U+30D6
ブ
Katakana
KATAKANA LETTER PU
1.1
U+30D7
プ
Katakana
KATAKANA LETTER HE
1.1
U+30D8
ヘ
Katakana
KATAKANA LETTER BE
1.1
U+30D9
ベ
Katakana
KATAKANA LETTER PE
1.1
U+30DA
ペ
Katakana
KATAKANA LETTER HO
1.1
U+30DB
ホ
Katakana
KATAKANA LETTER BO
1.1
U+30DC
ボ
Katakana
KATAKANA LETTER PO
1.1
U+30DD
ポ
Katakana
KATAKANA LETTER MA
1.1
U+30DE
マ
Katakana
KATAKANA LETTER MI
1.1
U+30DF
ミ
Katakana
KATAKANA LETTER MU
1.1
U+30E0
ム
Katakana
KATAKANA LETTER ME
1.1
U+30E1
メ
Katakana
KATAKANA LETTER MO
1.1
U+30E2
モ
Katakana
KATAKANA LETTER SMALL YA
1.1
U+30E3
ャ
Katakana
KATAKANA LETTER YA
1.1
U+30E4
ヤ
Katakana
KATAKANA LETTER SMALL YU
1.1
U+30E5
ュ
Katakana
KATAKANA LETTER YU
1.1
U+30E6
ユ
Katakana
KATAKANA LETTER SMALL YO
1.1
U+30E7
ョ
Katakana
KATAKANA LETTER YO
1.1
U+30E8
ヨ
Katakana
KATAKANA LETTER RA
1.1
U+30E9
ラ
Katakana
KATAKANA LETTER RI
1.1
U+30EA
リ
Katakana
KATAKANA LETTER RU
1.1
U+30EB
ル
Katakana
KATAKANA LETTER RE
1.1
U+30EC
レ
Katakana
KATAKANA LETTER RO
1.1
U+30ED
ロ
Katakana
KATAKANA LETTER SMALL WA
1.1
U+30EE
ヮ
Katakana
KATAKANA LETTER WA
1.1
U+30EF
ワ
Katakana
KATAKANA LETTER WI
1.1
U+30F0
ヰ
Katakana
KATAKANA LETTER WE
1.1
U+30F1
ヱ
Katakana
KATAKANA LETTER WO
1.1
U+30F2
ヲ
Katakana
KATAKANA LETTER N
1.1
U+30F3
ン
Katakana
KATAKANA LETTER VU
1.1
U+30F4
ヴ
Katakana
KATAKANA LETTER SMALL KA
1.1
U+30F5
ヵ
Katakana
KATAKANA LETTER SMALL KE
1.1
U+30F6
ヶ
Katakana
KATAKANA LETTER VA
1.1
U+30F7
ヷ
Katakana
KATAKANA LETTER VI
1.1
U+30F8
ヸ
Katakana
KATAKANA LETTER VE
1.1
U+30F9
ヹ
Katakana
KATAKANA LETTER VO
1.1
U+30FA
ヺ
Katakana
KATAKANA MIDDLE DOT
1.1
U+30FB
・
Katakana
KATAKANA-HIRAGANA PROLONGED SOUND MARK
1.1
U+30FC
ー
Katakana
KATAKANA ITERATION MARK
1.1
U+30FD
ヽ
Katakana
KATAKANA VOICED ITERATION MARK
1.1
U+30FE
ヾ
Katakana
KATAKANA DIGRAPH KOTO
3.2
U+30FF
ヿ
Katakana_Ext
KATAKANA LETTER SMALL KU
3.2
U+31F0
ㇰ
Katakana_Ext
KATAKANA LETTER SMALL SI
3.2
U+31F1
ㇱ
Katakana_Ext
KATAKANA LETTER SMALL SU
3.2
U+31F2
ㇲ
Katakana_Ext
KATAKANA LETTER SMALL TO
3.2
U+31F3
ㇳ
Katakana_Ext
KATAKANA LETTER SMALL NU
3.2
U+31F4
ㇴ
Katakana_Ext
KATAKANA LETTER SMALL HA
3.2
U+31F5
ㇵ
Katakana_Ext
KATAKANA LETTER SMALL HI
3.2
U+31F6
ㇶ
Katakana_Ext
KATAKANA LETTER SMALL HU
3.2
U+31F7
ㇷ
Katakana_Ext
KATAKANA LETTER SMALL HE
3.2
U+31F8
ㇸ
Katakana_Ext
KATAKANA LETTER SMALL HO
3.2
U+31F9
ㇹ
Katakana_Ext
KATAKANA LETTER SMALL MU
3.2
U+31FA
ㇺ
Katakana_Ext
KATAKANA LETTER SMALL RA
3.2
U+31FB
ㇻ
Katakana_Ext
KATAKANA LETTER SMALL RI
3.2
U+31FC
ㇼ
Katakana_Ext
KATAKANA LETTER SMALL RU
3.2
U+31FD
ㇽ
Katakana_Ext
KATAKANA LETTER SMALL RE
3.2
U+31FE
ㇾ
Katakana_Ext
KATAKANA LETTER SMALL RO
3.2
U+31FF
ㇿ
Half_And_Full_Forms
FULLWIDTH EXCLAMATION MARK
1.1
U+FF01
!
Half_And_Full_Forms
FULLWIDTH QUOTATION MARK
1.1
U+FF02
"
Half_And_Full_Forms
FULLWIDTH NUMBER SIGN
1.1
U+FF03
#
Half_And_Full_Forms
FULLWIDTH DOLLAR SIGN
1.1
U+FF04
$
Half_And_Full_Forms
FULLWIDTH PERCENT SIGN
1.1
U+FF05
%
Half_And_Full_Forms
FULLWIDTH AMPERSAND
1.1
U+FF06
&
Half_And_Full_Forms
FULLWIDTH APOSTROPHE
1.1
U+FF07
'
Half_And_Full_Forms
FULLWIDTH LEFT PARENTHESIS
1.1
U+FF08
(
Half_And_Full_Forms
FULLWIDTH RIGHT PARENTHESIS
1.1
U+FF09
)
Half_And_Full_Forms
FULLWIDTH ASTERISK
1.1
U+FF0A
*
Half_And_Full_Forms
FULLWIDTH PLUS SIGN
1.1
U+FF0B
+
Half_And_Full_Forms
FULLWIDTH COMMA
1.1
U+FF0C
,
Half_And_Full_Forms
FULLWIDTH HYPHEN-MINUS
1.1
U+FF0D
-
Half_And_Full_Forms
FULLWIDTH FULL STOP
1.1
U+FF0E
.
Half_And_Full_Forms
FULLWIDTH SOLIDUS
1.1
U+FF0F
/
Half_And_Full_Forms
FULLWIDTH DIGIT ZERO
1.1
U+FF10
0
Half_And_Full_Forms
FULLWIDTH DIGIT ONE
1.1
U+FF11
1
Half_And_Full_Forms
FULLWIDTH DIGIT TWO
1.1
U+FF12
2
Half_And_Full_Forms
FULLWIDTH DIGIT THREE
1.1
U+FF13
3
Half_And_Full_Forms
FULLWIDTH DIGIT FOUR
1.1
U+FF14
4
Half_And_Full_Forms
FULLWIDTH DIGIT FIVE
1.1
U+FF15
5
Half_And_Full_Forms
FULLWIDTH DIGIT SIX
1.1
U+FF16
6
Half_And_Full_Forms
FULLWIDTH DIGIT SEVEN
1.1
U+FF17
7
Half_And_Full_Forms
FULLWIDTH DIGIT EIGHT
1.1
U+FF18
8
Half_And_Full_Forms
FULLWIDTH DIGIT NINE
1.1
U+FF19
9
Half_And_Full_Forms
FULLWIDTH COLON
1.1
U+FF1A
:
Half_And_Full_Forms
FULLWIDTH SEMICOLON
1.1
U+FF1B
;
Half_And_Full_Forms
FULLWIDTH LESS-THAN SIGN
1.1
U+FF1C
<
Half_And_Full_Forms
FULLWIDTH EQUALS SIGN
1.1
U+FF1D
=
Half_And_Full_Forms
FULLWIDTH GREATER-THAN SIGN
1.1
U+FF1E
>
Half_And_Full_Forms
FULLWIDTH QUESTION MARK
1.1
U+FF1F
?
Half_And_Full_Forms
FULLWIDTH COMMERCIAL AT
1.1
U+FF20
@
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER A
1.1
U+FF21
A
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER B
1.1
U+FF22
B
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER C
1.1
U+FF23
C
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER D
1.1
U+FF24
D
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER E
1.1
U+FF25
E
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER F
1.1
U+FF26
F
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER G
1.1
U+FF27
G
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER H
1.1
U+FF28
H
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER I
1.1
U+FF29
I
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER J
1.1
U+FF2A
J
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER K
1.1
U+FF2B
K
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER L
1.1
U+FF2C
L
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER M
1.1
U+FF2D
M
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER N
1.1
U+FF2E
N
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER O
1.1
U+FF2F
O
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER P
1.1
U+FF30
P
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER Q
1.1
U+FF31
Q
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER R
1.1
U+FF32
R
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER S
1.1
U+FF33
S
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER T
1.1
U+FF34
T
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER U
1.1
U+FF35
U
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER V
1.1
U+FF36
V
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER W
1.1
U+FF37
W
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER X
1.1
U+FF38
X
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER Y
1.1
U+FF39
Y
Half_And_Full_Forms
FULLWIDTH LATIN CAPITAL LETTER Z
1.1
U+FF3A
Z
Half_And_Full_Forms
FULLWIDTH LEFT SQUARE BRACKET
1.1
U+FF3B
[
Half_And_Full_Forms
FULLWIDTH REVERSE SOLIDUS
1.1
U+FF3C
\
Half_And_Full_Forms
FULLWIDTH RIGHT SQUARE BRACKET
1.1
U+FF3D
]
Half_And_Full_Forms
FULLWIDTH CIRCUMFLEX ACCENT
1.1
U+FF3E
^
Half_And_Full_Forms
FULLWIDTH LOW LINE
1.1
U+FF3F
_
Half_And_Full_Forms
FULLWIDTH GRAVE ACCENT
1.1
U+FF40
`
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER A
1.1
U+FF41
a
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER B
1.1
U+FF42
b
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER C
1.1
U+FF43
c
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER D
1.1
U+FF44
d
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER E
1.1
U+FF45
e
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER F
1.1
U+FF46
f
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER G
1.1
U+FF47
g
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER H
1.1
U+FF48
h
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER I
1.1
U+FF49
i
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER J
1.1
U+FF4A
j
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER K
1.1
U+FF4B
k
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER L
1.1
U+FF4C
l
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER M
1.1
U+FF4D
m
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER N
1.1
U+FF4E
n
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER O
1.1
U+FF4F
o
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER P
1.1
U+FF50
p
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER Q
1.1
U+FF51
q
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER R
1.1
U+FF52
r
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER S
1.1
U+FF53
s
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER T
1.1
U+FF54
t
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER U
1.1
U+FF55
u
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER V
1.1
U+FF56
v
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER W
1.1
U+FF57
w
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER X
1.1
U+FF58
x
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER Y
1.1
U+FF59
y
Half_And_Full_Forms
FULLWIDTH LATIN SMALL LETTER Z
1.1
U+FF5A
z
Half_And_Full_Forms
FULLWIDTH LEFT CURLY BRACKET
1.1
U+FF5B
{
Half_And_Full_Forms
FULLWIDTH VERTICAL LINE
1.1
U+FF5C
|
Half_And_Full_Forms
FULLWIDTH RIGHT CURLY BRACKET
1.1
U+FF5D
}
Half_And_Full_Forms
FULLWIDTH TILDE
1.1
U+FF5E
~
Half_And_Full_Forms
HALFWIDTH IDEOGRAPHIC FULL STOP
1.1
U+FF61
。
Half_And_Full_Forms
HALFWIDTH LEFT CORNER BRACKET
1.1
U+FF62
「
Half_And_Full_Forms
HALFWIDTH RIGHT CORNER BRACKET
1.1
U+FF63
」
Half_And_Full_Forms
HALFWIDTH IDEOGRAPHIC COMMA
1.1
U+FF64
、
Half_And_Full_Forms
HALFWIDTH KATAKANA MIDDLE DOT
1.1
U+FF65
・
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER WO
1.1
U+FF66
ヲ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL A
1.1
U+FF67
ァ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL I
1.1
U+FF68
ィ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL U
1.1
U+FF69
ゥ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL E
1.1
U+FF6A
ェ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL O
1.1
U+FF6B
ォ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL YA
1.1
U+FF6C
ャ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL YU
1.1
U+FF6D
ュ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL YO
1.1
U+FF6E
ョ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SMALL TU
1.1
U+FF6F
ッ
Half_And_Full_Forms
HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
1.1
U+FF70
ー
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER A
1.1
U+FF71
ア
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER I
1.1
U+FF72
イ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER U
1.1
U+FF73
ウ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER E
1.1
U+FF74
エ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER O
1.1
U+FF75
オ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER KA
1.1
U+FF76
カ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER KI
1.1
U+FF77
キ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER KU
1.1
U+FF78
ク
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER KE
1.1
U+FF79
ケ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER KO
1.1
U+FF7A
コ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SA
1.1
U+FF7B
サ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SI
1.1
U+FF7C
シ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SU
1.1
U+FF7D
ス
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SE
1.1
U+FF7E
セ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER SO
1.1
U+FF7F
ソ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER TA
1.1
U+FF80
タ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER TI
1.1
U+FF81
チ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER TU
1.1
U+FF82
ツ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER TE
1.1
U+FF83
テ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER TO
1.1
U+FF84
ト
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER NA
1.1
U+FF85
ナ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER NI
1.1
U+FF86
ニ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER NU
1.1
U+FF87
ヌ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER NE
1.1
U+FF88
ネ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER NO
1.1
U+FF89
ノ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER HA
1.1
U+FF8A
ハ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER HI
1.1
U+FF8B
ヒ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER HU
1.1
U+FF8C
フ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER HE
1.1
U+FF8D
ヘ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER HO
1.1
U+FF8E
ホ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER MA
1.1
U+FF8F
マ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER MI
1.1
U+FF90
ミ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER MU
1.1
U+FF91
ム
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER ME
1.1
U+FF92
メ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER MO
1.1
U+FF93
モ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER YA
1.1
U+FF94
ヤ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER YU
1.1
U+FF95
ユ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER YO
1.1
U+FF96
ヨ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER RA
1.1
U+FF97
ラ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER RI
1.1
U+FF98
リ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER RU
1.1
U+FF99
ル
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER RE
1.1
U+FF9A
レ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER RO
1.1
U+FF9B
ロ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER WA
1.1
U+FF9C
ワ
Half_And_Full_Forms
HALFWIDTH KATAKANA LETTER N
1.1
U+FF9D
ン
Half_And_Full_Forms
HALFWIDTH KATAKANA VOICED SOUND MARK
1.1
U+FF9E
゙
Half_And_Full_Forms
HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
1.1
U+FF9F
゚
おわりに
Unicode Normalization Form って使いづらいなぁと思って、ネットで調べてみても、この仕様に否定的な記事はあまり見つかりませんでした。
みなさん、norm や width をそのまま使ってるんですかね?
それとも、特に難しくもないからみんな独自にライブラリを作ってるのかな?
あ、そもそもノーマライズとかしてないんでしょうか?
それが気になってます。誰か教えてください(笑)
また、Golang を触り始めてからまだ日が浅いので、ライブラリの実装に抜けがあるかもしれません。
- Go らしくない部分
- 非効率な箇所
- バグ
などを見つけたら教えてもらえると嬉しいです。
それでは!