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';

コメントを残す