postgreSQL(ポスグレ)で、ひらがな・カタカナをローマ字変換する関数が欲しかったので作成しました。
仕様としては、kana_to_roman(‘きょうのカムチャッカのてんきは?’) と入れると、
KYONOKAMUCHAKKANOTENKIHA?
というtextを返してくれるものです。
変換方法はヘボン式のローマ字変換です。
ヘボン式については、こちらのサイト(http://www.seikatubunka.metro.tokyo.jp/hebon/)を参考にしました。
ヘボン式など意識せずに簡単にやるなら、1対1で対応するひらがな・カナを対応する英字に変換すればよい訳ですが、そうは行かず。
以下の特殊ルールが少し面倒でしたが対応しています。
■「ん」は「N」で表記。
ただし、B・M・Pの前では、「ん」は「M」で表記(なんば NAMBA/ほんま HOMMA/まんぽ MAMPO)
■「っ」は子音を重ねる→ (例) べっぷ BEPPU/いっしき ISSHIKI
ただし、CHの前では、「っ」は「T」で表記。(えっちゅう ETCHU/はっちょう HATCHO)
■長音:「O」や「U」は記入しない→ (例) おおの ONO/さいとう SAITO
postgreSQL(ポスグレ)の関数のソースコードは以下です。
PostgreSQL 9.3.4 で動作確認済みです。
↓ バージョン9.1以上用のソースコード
CREATE OR REPLACE FUNCTION kana_to_roman(TEXT) RETURNS TEXT AS $$ DECLARE _input_s ALIAS FOR $1; s TEXT; i INTEGER :=1; len INTEGER ; hebon TEXT :='' ; lastHebon TEXT := ''; lastChar TEXT := ''; nextChar TEXT := ''; c TEXT ; -- カレント文字 c2 TEXT ; -- カレント2文字 h TEXT ; -- hebon nc TEXT ; -- 次の文字 nc2 TEXT ; -- 次の2文字 nh TEXT ; --次のヘボン testH TEXT :=''; --長音のテスト用ヘボン a TEXT; cnt INTEGER; target TEXT[] := ARRAY[ 'A','I','U','E','O' ,'KA','KI','KU','KE','KO' ,'SA','SHI','SU','SE','SO' ,'TA','CHI','TSU','TE','TO' ,'NA','NI','NU','NE','NO' ,'HA','HI','FU','HE','HO' ,'MA','MI','MU','ME','MO' ,'YA','YU','YO' ,'RA','RI','RU','RE','RO' ,'WA','I','E','O' ,'A','I','U','E','O' ,'GA','GI','GU','GE','GO' ,'ZA','JI','ZU','ZE','ZO' ,'DA','JI','ZU','DE','DO' ,'BA','BI','BU','BE','BO' ,'PA','PI','PU','PE','PO' ,'KYA','KYU','KYO' ,'SYA','SHU','SYO' ,'CHA','CHU','CHO','CHE' ,'NYA','NYU','NYO' ,'HYA','HYU','HYO' ,'MYA','MYU','MYO' ,'RYA','RYU','RYO' ,'GYA','GYU','GYO' ,'JA','JU','JO' ,'BYA','BYU','BYO' ,'PYA','PYU','PYO' ,'V' ]; source TEXT[] := ARRAY[ 'ア','イ','ウ','エ','オ' ,'カ','キ','ク','ケ','コ' ,'サ','シ','ス','セ','ソ' ,'タ','チ','ツ','テ','ト' ,'ナ','ニ','ヌ','ネ','ノ' ,'ハ','ヒ','フ','ヘ','ホ' ,'マ','ミ','ム','メ','モ' ,'ヤ','ユ','ヨ' ,'ラ','リ','ル','レ','ロ' ,'ワ','ヰ','ヱ','ヲ' -- ン は別途 ,'ァ','ィ','ゥ','ェ','ォ' ,'ガ','ギ','グ','ゲ','ゴ' ,'ザ','ジ','ズ','ゼ','ゾ' ,'ダ','ジ','ヅ','デ','ド' ,'バ','ビ','ブ','ベ','ボ' ,'パ','ピ','プ','ペ','ポ' ,'キャ','キュ','キョ' ,'シャ','シュ','ショ' ,'チャ','チュ','チョ','チェ' ,'ニャ','ニュ','ニョ' ,'ヒャ','ヒュ','ヒョ' ,'ミャ','ミュ','ミョ' ,'リャ','リュ','リョ' ,'ギャ','ギュ','ギョ' ,'ジャ','ジュ','ジョ' ,'ビャ','ビュ','ビョ' ,'ピャ','ピュ','ピョ' ,'ヴ' ]; BEGIN cnt := 0; s := translate(_input_s ,'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよ らりるれろ わをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽっゃゅょーゐゑ' ,'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨ ラリルレロ ワヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポッャュョーイエ' ); len := LENGTH(s); i := 1; WHILE i<=len LOOP h := ''; c := ''; c2 := ''; cnt := 0; -- 1文字 c := SUBSTR(s,i,1); -- 2文字 IF (i<len) THEN c2 := SUBSTR(s,i,2); ELSE c2 := ''; END IF; cnt:=0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = c2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからhに格納 h := target[cnt]; END IF; END LOOP; IF (h='') THEN c2 := ''; cnt := 0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = c THEN -- 2文字がマップになければ1文字分の変換後文字をマップからhに格納 h := target[cnt]; END IF; END LOOP; END IF; IF h='' THEN h:=c; END IF; IF c2<>'' THEN c:=c2 ; END IF; IF i<len THEN nc := SUBSTR(s,i+1,1); ELSE nc := ''; END IF; IF c = 'ッ' THEN nh := ''; nc2 := ''; IF(i+2<=len) THEN nc2 := SUBSTR(s,i+1,2); cnt:=0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF (i+1<=len) AND nh='' THEN nc2 := SUBSTR(s,i+1,1); cnt:=0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF nh != '' THEN IF POSITION('CH' in nh)=1 THEN h:='T'; ELSE h:=SUBSTRING(nh,1,1); END IF; END IF; ELSEIF c = 'ン' THEN nh := ''; nc2 := ''; h:='n'; IF(i+2<=len) THEN nc2 := SUBSTR(s,i+1,2); cnt:=0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF (i+1<=len) AND nh='' THEN nc2 := SUBSTR(s,i+1,1); cnt:=0; FOREACH a IN ARRAY source LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF nh != '' AND ( POSITION('B' in nh)=1 OR POSITION('M' in nh)=1 OR POSITION( 'P' in nh) =1 ) THEN h:='M'; ELSE h:='N'; END IF; ELSEIF c = 'ー' THEN h:=''; END IF; IF h != '' THEN IF lastHebon!='' THEN testH := lastHebon || h; IF LENGTH(testH) >= 2 THEN testH := SUBSTRING(testH,LENGTH(testH)-1,2); IF (testH='AA' OR testH='II' OR testH='UU' OR testH='EE' OR testH= 'OO' OR testH='OU') THEN h:=''; END IF; END IF; END IF; END IF; hebon:=hebon || h; lastChar := c; lastHebon := h; i := i+LENGTH(c); END LOOP; RETURN hebon; END; $$ LANGUAGE 'plpgsql';
上記ソースは、plpgsql の FOREACH 文を使っていますが、FOREACH は バージョン9.1以上から使える制御文です。
配列走査には、このFOREACHを使った方が速いそうです。
バージョン9.0以下でも動作するソースも、以下に貼り付けておきます。
PostgreSQL 8.2.9 で動作確認済みです。
↓FOREACHが使えないバージョン9.0以下用のソースコード
CREATE OR REPLACE FUNCTION kana_to_roman(TEXT) RETURNS TEXT AS $$ DECLARE _input_s ALIAS FOR $1; s TEXT; i INTEGER :=1; len INTEGER ; hebon TEXT :='' ; lastHebon TEXT := ''; lastChar TEXT := ''; nextChar TEXT := ''; c TEXT ; -- カレント文字 c2 TEXT ; -- カレント2文字 h TEXT ; -- hebon nc TEXT ; -- 次の文字 nc2 TEXT ; -- 次の2文字 nh TEXT ; --次のヘボン testH TEXT :=''; --長音のテスト用ヘボン a TEXT; cnt INTEGER; target TEXT[] := ARRAY[ 'A','I','U','E','O' ,'KA','KI','KU','KE','KO' ,'SA','SHI','SU','SE','SO' ,'TA','CHI','TSU','TE','TO' ,'NA','NI','NU','NE','NO' ,'HA','HI','FU','HE','HO' ,'MA','MI','MU','ME','MO' ,'YA','YU','YO' ,'RA','RI','RU','RE','RO' ,'WA','I','E','O' ,'A','I','U','E','O' ,'GA','GI','GU','GE','GO' ,'ZA','JI','ZU','ZE','ZO' ,'DA','JI','ZU','DE','DO' ,'BA','BI','BU','BE','BO' ,'PA','PI','PU','PE','PO' ,'KYA','KYU','KYO' ,'SYA','SHU','SYO' ,'CHA','CHU','CHO','CHE' ,'NYA','NYU','NYO' ,'HYA','HYU','HYO' ,'MYA','MYU','MYO' ,'RYA','RYU','RYO' ,'GYA','GYU','GYO' ,'JA','JU','JO' ,'BYA','BYU','BYO' ,'PYA','PYU','PYO' ,'V' ]; source TEXT[] := ARRAY[ 'ア','イ','ウ','エ','オ' ,'カ','キ','ク','ケ','コ' ,'サ','シ','ス','セ','ソ' ,'タ','チ','ツ','テ','ト' ,'ナ','ニ','ヌ','ネ','ノ' ,'ハ','ヒ','フ','ヘ','ホ' ,'マ','ミ','ム','メ','モ' ,'ヤ','ユ','ヨ' ,'ラ','リ','ル','レ','ロ' ,'ワ','ヰ','ヱ','ヲ' -- ン は別途 ,'ァ','ィ','ゥ','ェ','ォ' ,'ガ','ギ','グ','ゲ','ゴ' ,'ザ','ジ','ズ','ゼ','ゾ' ,'ダ','ジ','ヅ','デ','ド' ,'バ','ビ','ブ','ベ','ボ' ,'パ','ピ','プ','ペ','ポ' ,'キャ','キュ','キョ' ,'シャ','シュ','ショ' ,'チャ','チュ','チョ','チェ' ,'ニャ','ニュ','ニョ' ,'ヒャ','ヒュ','ヒョ' ,'ミャ','ミュ','ミョ' ,'リャ','リュ','リョ' ,'ギャ','ギュ','ギョ' ,'ジャ','ジュ','ジョ' ,'ビャ','ビュ','ビョ' ,'ピャ','ピュ','ピョ' ,'ヴ' ]; BEGIN cnt := 0; s := translate(_input_s ,'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよ らりるれろ わをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽっゃゅょーゐゑ' ,'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨ ラリルレロ ワヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポッャュョーイエ' ); len := LENGTH(s); i := 1; WHILE i<=len LOOP h := ''; c := ''; c2 := ''; cnt := 0; -- 1文字 c := SUBSTR(s,i,1); -- 2文字 IF (i<len) THEN c2 := SUBSTR(s,i,2); ELSE c2 := ''; END IF; cnt:=0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = c2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからhに格納 h := target[cnt]; END IF; END LOOP; IF (h='') THEN c2 := ''; cnt := 0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = c THEN -- 2文字がマップになければ1文字分の変換後文字をマップからhに格納 h := target[cnt]; END IF; END LOOP; END IF; IF h='' THEN h:=c; END IF; IF c2<>'' THEN c:=c2 ; END IF; IF i<len THEN nc := SUBSTR(s,i+1,1); ELSE nc := ''; END IF; IF c = 'ッ' THEN nh := ''; nc2 := ''; IF(i+2<=len) THEN nc2 := SUBSTR(s,i+1,2); cnt:=0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF (i+1<=len) AND nh='' THEN nc2 := SUBSTR(s,i+1,1); cnt:=0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF nh != '' THEN IF POSITION('CH' in nh)=1 THEN h:='T'; ELSE h:=SUBSTRING(nh,1,1); END IF; END IF; ELSEIF c = 'ン' THEN nh := ''; nc2 := ''; h:='n'; IF(i+2<=len) THEN nc2 := SUBSTR(s,i+1,2); cnt:=0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF (i+1<=len) AND nh='' THEN nc2 := SUBSTR(s,i+1,1); cnt:=0; -- FOREACH a IN ARRAY source LOOP FOR j IN ARRAY_LOWER(source,1)..ARRAY_UPPER(source,1) LOOP cnt:=cnt+1; IF source[cnt] = nc2 THEN -- 2文字がマップにあれば2文字分の変換後文字をマップからnhに格納 nh := target[cnt]; END IF; END LOOP; END IF; IF nh != '' AND ( POSITION('B' in nh)=1 OR POSITION('M' in nh)=1 OR POSITION( 'P' in nh) =1 ) THEN h:='M'; ELSE h:='N'; END IF; ELSEIF c = 'ー' THEN h:=''; END IF; IF h != '' THEN IF lastHebon!='' THEN testH := lastHebon || h; IF LENGTH(testH) >= 2 THEN testH := SUBSTRING(testH,LENGTH(testH)-1,2); IF (testH='AA' OR testH='II' OR testH='UU' OR testH='EE' OR testH= 'OO' OR testH='OU') THEN h:=''; END IF; END IF; END IF; END IF; hebon:=hebon || h; lastChar := c; lastHebon := h; i := i+LENGTH(c); END LOOP; RETURN hebon; END; $$ LANGUAGE 'plpgsql';
コメントを残す