tl;dr
- ひらがなとカタカナは Unicode で 96 文字ずつある
- ひらがなとカタカナの Unicode 符号位置は 96 文字ずれている
- ひらがなの rune に 96 を足せばカタカナになる
- カタカナの rune に 96 を引けばひらがなになる
- rune がひらがなかどうかは
unicode.In(r, unicode.Hiragana)
で判定できる - rune がカタカナかどうかは
unicode.In(r, unicode.Katakana)
で判定できる
ひらがなとカタカナの Unicode 符号位置
http://www.unicodemap.org/range/62/Hiragana/ と http://www.unicodemap.org/range/63/Katakana/ が見やすい。
それぞれ 0x3041 と 0x30a1 からはじまる。
実装コード
HiraganaToKatakana 関数は文字列中のひらがなをカタカナに変換して返す。
KatakanaToHiragana 関数は文字列中のカタカナをひらがなに変換して返す。
package kana
import (
"unicode"
)
const (
// http://www.unicodemap.org/range/62/Hiragana/
hiraganaLo = 0x3041 // ぁ
// http://www.unicodemap.org/range/63/Katakana/
katakanaLo = 0x30a1 // ァ
codeDiff = katakanaLo - hiraganaLo
)
// HiraganaToKatakana はひらがなをカタカナに変換する。
func HiraganaToKatakana(str string) string {
src := []rune(str)
dst := make([]rune, len(src))
for i, r := range src {
switch {
case unicode.In(r, unicode.Hiragana):
dst[i] = r + codeDiff
default:
dst[i] = r
}
}
return string(dst)
}
// KatakanaToHiragana はカタカナをひらがなに変換する。
func KatakanaToHiragana(str string) string {
src := []rune(str)
dst := make([]rune, len(src))
for i, r := range src {
switch {
case unicode.In(r, unicode.Katakana):
dst[i] = r - codeDiff
default:
dst[i] = r
}
}
return string(dst)
}
テストコード
package kana_test
import (
"testing"
"path/to/kana"
)
func TestHiraganaToKatakana(t *testing.T) {
tests := []struct {
input string
want string
}{
{
input: "",
want: "",
},
{
input: "あいうえお",
want: "アイウエオ",
},
{
input: "アイウエオ",
want: "アイウエオ",
},
{
input: "あいウえお",
want: "アイウエオ",
},
{
input: "あいuえお",
want: "アイuエオ",
},
{
input: "あいUえお",
want: "アイUエオ",
},
{
input: "あい雨えお",
want: "アイ雨エオ",
},
}
for i, test := range tests {
got := kana.HiraganaToKatakana(test.input)
if got != test.want {
t.Errorf("[%d] got %s, but want %s", i, got, test.want)
}
}
}
func TestKatakanaToHiragana(t *testing.T) {
tests := []struct {
input string
want string
}{
{
input: "",
want: "",
},
{
input: "アイウエオ",
want: "あいうえお",
},
{
input: "あいうえお",
want: "あいうえお",
},
{
input: "アイうエオ",
want: "あいうえお",
},
{
input: "アイuエオ",
want: "あいuえお",
},
{
input: "アイUエオ",
want: "あいUえお",
},
{
input: "アイ雨エオ",
want: "あい雨えお",
},
}
for i, test := range tests {
got := kana.KatakanaToHiragana(test.input)
if got != test.want {
t.Errorf("[%d] got %s, but want %s", i, got, test.want)
}
}
}