RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【Java】MAN WITH A MISSIONの呟きっぽいテキストをつくろう(平仮名⇒片仮名変換)

暇だったので、MAN WITH A MISSION呟き用の変換ロジックをつくった
ただ単に「平仮名を片仮名に変換する」というただそれだけのロジックであるが…



 

 

「平仮名」はU+3040~U+309F(96個)
「片仮名」はU+30A0~U+30FF(96個)
で、
平仮名の後にそのまま続けて片仮名が位置づいており、
同音になる文字は平仮名と片仮名でブロックの中の相対的位置が一致している。
(たとえば「あ」は平仮名ブロックで前から2番目、「ア」は片仮名ブロックで前から2番目)
このため平仮名⇒片仮名の変換は単純にこの差だけコードポイントをズラしてやれば可能である。
ちなみにその差は96である。

ただ入力文字全てに対してコードポイントを96ズラすと、
入力文字内に平仮名以外があったときは意味不明な文章になってしまう(※)ので、
「平仮名だったら片仮名にするが、それ以外はそのまま」というような考慮が必要である。
実際、MAN WITH A MISSION公式のツイート等を見ても、漢字はそのまま漢字になっており、
コードポイントを意図的に96ズラした後とおもえる様子はない(当然だが…)。

(※)例えば「田中先輩」を96ずつコードポイントをズラすと
「田」U+7530⇒「疐」U+7590
「中」U+4E2D⇒「亍」U+4E8D
「先」U+5148⇒「冨」U+51A8
「輩」U+8F29⇒「辉」U+8F89
になって意味不明になる。

というわけで「平仮名を片仮名に変換する」を実装してみると

	private static String dogDays(String str) {
		if (str == null) {
			return "";
		}
		
		StringBuilder sb = new StringBuilder();
		for (int i=0; i < str.length(); i++) {
		
			char ch = str.charAt(i);
			// 平仮名の範囲の文字か判定する
			if (ch >= '\u3040' && ch <= '\u309f') {
				ch = (char)(ch + 96); // 平仮名なら、コードポイントを96だけ単純にずらす
			}
			sb.append(ch);
		}
		
		sb.append("(¬з¬)");
		
		return sb.toString();
	
	}

こんなかんじか。
メソッド名がDog Daysなのと
変換後にタナパイサイン"(¬з¬)"が付くのはご愛嬌である。

「平仮名かどうか」の判定はch >= '\u3040' && ch <= '\u309f'である。
Stringを1文字ずつ取り出し(String#charAt)、
その1文字1文字について↑の判定を施して、
その文字が平仮名かどうか判定する。

実行例は↓なかんじ。

20171006_neta_mwam_conv_test.jpg




ちなみにこれの実装に従うと、平仮名⇒片仮名の変換の対応は以下の通りとなる。

変換前コードポイント変換前文字変換後コードポイント変換後文字

U+3040   U+30A0
U+3041 U+30A1
U+3042 U+30A2
U+3043 U+30A3
U+3044 U+30A4
U+3045 U+30A5
U+3046 U+30A6
U+3047 U+30A7
U+3048 U+30A8
U+3049 U+30A9
U+304A U+30AA
U+304B U+30AB
U+304C U+30AC
U+304D U+30AD
U+304E U+30AE
U+304F U+30AF
U+3050 U+30B0
U+3051 U+30B1
U+3052 U+30B2
U+3053 U+30B3
U+3054 U+30B4
U+3055 U+30B5
U+3056 U+30B6
U+3057 U+30B7
U+3058 U+30B8
U+3059 U+30B9
U+305A U+30BA
U+305B U+30BB
U+305C U+30BC
U+305D U+30BD
U+305E U+30BE
U+305F U+30BF
U+3060 U+30C0
U+3061 U+30C1
U+3062 U+30C2
U+3063 U+30C3
U+3064 U+30C4
U+3065 U+30C5
U+3066 U+30C6
U+3067 U+30C7
U+3068 U+30C8
U+3069 U+30C9
U+306A U+30CA
U+306B U+30CB
U+306C U+30CC
U+306D U+30CD
U+306E U+30CE
U+306F U+30CF
U+3070 U+30D0
U+3071 U+30D1
U+3072 U+30D2
U+3073 U+30D3
U+3074 U+30D4
U+3075 U+30D5
U+3076 U+30D6
U+3077 U+30D7
U+3078 U+30D8
U+3079 U+30D9
U+307A U+30DA
U+307B U+30DB
U+307C U+30DC
U+307D U+30DD
U+307E U+30DE
U+307F U+30DF
U+3080 U+30E0
U+3081 U+30E1
U+3082 U+30E2
U+3083 U+30E3
U+3084 U+30E4
U+3085 U+30E5
U+3086 U+30E6
U+3087 U+30E7
U+3088 U+30E8
U+3089 U+30E9
U+308A U+30EA
U+308B U+30EB
U+308C U+30EC
U+308D U+30ED
U+308E U+30EE
U+308F U+30EF
U+3090 U+30F0
U+3091 U+30F1
U+3092 U+30F2
U+3093 U+30F3
U+3094 U+30F4
U+3095 U+30F5
U+3096 U+30F6
U+3097   U+30F7
U+3098   U+30F8
U+3099 U+30F9
U+309A U+30FA
U+309B U+30FB
U+309C U+30FC
U+309D U+30FD
U+309E U+30FE
U+309F U+30FF


↑のWikipediaのページに寄れば、
U+3097、U+3098は、「平仮名のブロックではあるが未使用」となっている。
それに対して片仮名側のU+30F7、U+30F8は片仮名のブロックでちゃんと使用しており、字も登録されている。
「単純にコードポイントを96ずらした」だけだと上記の表のように対応付くが、
U+3097のような例はそもそも「変換元がない」というのが正確なところなので、
実際のところ「変換」には至ってないと考えるべきだろう。
(ちなみに同じ意味でU+3040も平仮名では未使用だそうだ)

上の表は機械的に出力したのでキーボードで打って出力したわけではないのだが、
「ゔ」とかそんな文字実在したんだなって感心してしまう。
どうやって出せるんだこの文字…
「う」に濁点ってカタカナだけの専売特許だと思ってたよ。。(ギュスターヴ、みたいなw)

ちなみに、文学というか、文字学?っていうのか(そんな学問があるのかどうかすら知らないが)
そういう観点でこの対応付けが正しいのかは検証してない、っていうか俺には無理。。
字の成り立ちや背景等を深堀していくと
「この片仮名は本来、その平仮名に対応付けるために作ったのではない」
(Unicode制定の都合でたまたま対応付く位置にいるだけで実際の意味は違うんだぜ!)
みたいのも実はあるんじゃねーの?とか薄ら思っていたりするのだ。
そうでもないのかね。




平仮名⇒片仮名が機械的に対応付けられる以上、その逆(片仮名⇒平仮名)も同様である。
そしてどちらかというとマンウィズ変換機の真似事をするよりは
マンウィズの呟きを日本語に逆変換するほうが需要が高いんじゃないかと思えてきた。
マンウィズのツイッターにアクセスして自動で片仮名⇒平仮名に変換しなおして表示する、
そんなスクリプトがあってもいいかもしれないね。
今度作ろうかなw