db의 반각 전각 변환

반각 가명으로 데이터를db에 넣고 DB의 전각 가명을 반각 가명으로 출력하려고 합니다.
나는 이것이 흔히 있는 일이라고 생각한다.
특히 금융과 의료 관련 시스템에서 필요한 조건이 되는 경우가 많다.
또 낡은 외부 결제 시스템과 판매 대행사를 이용하면 고객 명부와 상품명은 반각 가명의 csv로 발송되기도 한다.
이 데이터를 반각으로 변환하다↔전각에 너무 신경 쓰지 말고 시스템을 구축하길 바란다.
그러나 응용 프로그램에서 이 처리를 정의하면 다음과 같은 문제가 발생할 수 있다.

결점

  • 금융과 의료 관련 시스템의 경우 여러 공급업체가 자주 들어오는데, 여러 공급업체가 각각 다른 앱을 만들기 때문에 앱마다 각각 다른 반각 가나 전환 논리를 관리하기가 매우 어렵다.
  • 느린 애플리케이션 측 설치
  • 반각 가나의 처리는 업무에 있어서 상응하는 주파수로 집행되거나 대량 처리에 포함되기 때문에 일찍 처리하고 싶은 것도 있다.
    또 프로그램을 쓸 때는 지식보다는 종합적인 글자 대책과 반전 처리 등 간단한 프로그래밍 기술이 테스트된 처리이기 때문에 밖으로 던지지 않는 게 좋다고 생각한다.

    어떡하죠?


    위의 단점은 논리를 저장 주소로 보내고 응용 프로그램에서 참고하면 전체 시스템의 반쪽 가명 논리는 하나만 관리하면 간단해진다는 것이다.
    앞으로 한글 등 다른 문자의 전각 반각 지원이 늘어나면 여기에 추가 처리 기능 수정만 하면 끝난다.
    User 테이블의 열에서 사용할 때, 생성 열에서 저장 주소를 호출하면, 전각 가나의 데이터로 반각 가나를 표현할 수 있기 때문에 관리도 수월해진다.기존의 시스템이 모두 orm일지라도 orm와 호환성은 그다지 나쁘지 않다.

    소스 코드


    postgresql의 예는 다음과 같다.
    다른 RDBMS도 같은 요령이다.
    function에 immutable을 꼭 붙여주세요.
    만약 이것이 없다면 DB 변경을 일으키는 부작용을 일으킨 저장소 주소가 있는지
    DB 측에서 판별할 수 없기 때문에 생성 열을 사용할 수 없거나 다른 DB 처리에 큰 영향을 미친다.
    이는 다른 RDBMS에서도 마찬가지입니다.
    hankakukana2zenkaku_strig-> 반각 문자열을 전각 문자열의 저장 주소로 변경
    zenkaku2hankakukana_string-> 전체 문자열을 반각 문자열의 저장 주소로 변경
    CREATE FUNCTION zenkaku2hankakukana (c CHAR)
    RETURNS VARCHAR(2) AS $$
    DECLARE
        ret VARCHAR(2);
    BEGIN
    
        CASE c
            -- ア行
            WHEN 'ア' THEN
                ret := 'ア';
            WHEN 'イ' THEN
                ret := 'イ';
            WHEN 'ウ' THEN
                ret := 'ウ';
            WHEN 'エ' THEN
                ret := 'エ';
            WHEN 'オ' THEN
                ret := 'オ';
            -- カ行
            WHEN 'カ' THEN
                ret := 'カ';
            WHEN 'キ' THEN
                ret := 'キ';
            WHEN 'ク' THEN
                ret := 'ク';
            WHEN 'ケ' THEN
                ret := 'ケ';
            WHEN 'コ' THEN
                ret := 'コ';
            -- サ行
            WHEN 'サ' THEN
                ret := 'サ';
            WHEN 'シ' THEN
                ret := 'シ';
            WHEN 'ス' THEN
                ret := 'ス';
            WHEN 'セ' THEN
                ret := 'セ';
            WHEN 'ソ' THEN
                ret := 'ソ';
            -- タ行
            WHEN 'タ' THEN
                ret := 'タ';
            WHEN 'チ' THEN
                ret := 'チ';
            WHEN 'ツ' THEN
                ret := 'ツ';
            WHEN 'テ' THEN
                ret := 'テ';
            WHEN 'ト' THEN
                ret := 'ト';
            -- ナ行
            WHEN 'ナ' THEN
                ret := 'ナ';
            WHEN 'ニ' THEN
                ret := 'ニ';
            WHEN 'ヌ' THEN
                ret := 'ヌ';
            WHEN 'ネ' THEN
                ret := 'ネ';
            WHEN 'ノ' THEN
                ret := 'ノ';
            -- ハ行
            WHEN 'ハ' THEN
                ret := 'ハ';
            WHEN 'ヒ' THEN
                ret := 'ヒ';
            WHEN 'フ' THEN
                ret := 'フ';
            WHEN 'ヘ' THEN
                ret := 'ヘ';
            WHEN 'ホ' THEN
                ret := 'ホ';
            -- マ行
            WHEN 'マ' THEN
                ret := 'マ';
            WHEN 'ミ' THEN
                ret := 'ミ';
            WHEN 'ム' THEN
                ret := 'ム';
            WHEN 'メ' THEN
                ret := 'メ';
            WHEN 'モ' THEN
                ret := 'モ';
            -- ヤ行
            WHEN 'ヤ' THEN
                ret := 'ヤ';
            WHEN 'ユ' THEN
                ret := 'ユ';
            WHEN 'ヨ' THEN
                ret := 'ヨ';
            -- ワ行
            WHEN 'ワ' THEN
                ret := 'ワ';
            WHEN 'ヲ' THEN
                ret := 'ヲ';
            WHEN 'ン' THEN
                ret := 'ン';
            -- ガ行
            WHEN 'ガ' THEN
                ret := 'ガ';
            WHEN 'ギ' THEN
                ret := 'ギ';
            WHEN 'グ' THEN
                ret := 'グ';
            WHEN 'ゲ' THEN
                ret := 'ゲ';
            WHEN 'ゴ' THEN
                ret := 'ゴ';
            -- ザ行
            WHEN 'ザ' THEN
                ret := 'ザ';
            WHEN 'ジ' THEN
                ret := 'ジ';
            WHEN 'ズ' THEN
                ret := 'ズ';
            WHEN 'ゼ' THEN
                ret := 'ゼ';
            WHEN 'ゾ' THEN
                ret := 'ゾ';
            -- ダ行
            WHEN 'ダ' THEN
                ret := 'ダ';
            WHEN 'ヂ' THEN
                ret := 'ヂ';
            WHEN 'ヅ' THEN
                ret := 'ヅ';
            WHEN 'デ' THEN
                ret := 'デ';
            WHEN 'ド' THEN
                ret := 'ド';
            -- バ行
            WHEN 'バ' THEN
                ret := 'バ';
            WHEN 'ビ' THEN
                ret := 'ビ';
            WHEN 'ブ' THEN
                ret := 'ブ';
            WHEN 'ベ' THEN
                ret := 'ベ';
            WHEN 'ボ' THEN
                ret := 'ボ';
            -- パ行
            WHEN 'パ' THEN
                ret := 'パ';
            WHEN 'ピ' THEN
                ret := 'ピ';
            WHEN 'プ' THEN
                ret := 'プ';
            WHEN 'ペ' THEN
                ret := 'ペ';
            WHEN 'ポ' THEN
                ret := 'ポ';
            -- 小文字
            WHEN 'ァ' THEN
                ret := 'ァ';
            WHEN 'ィ' THEN
                ret := 'ィ';
            WHEN 'ゥ' THEN
                ret := 'ゥ';
            WHEN 'ェ' THEN
                ret := 'ェ';
            WHEN 'ォ' THEN
                ret := 'ォ';
            WHEN 'ッ' THEN
                ret := 'ッ';
            WHEN 'ャ' THEN
                ret := 'ャ';
            WHEN 'ュ' THEN
                ret := 'ュ';
            WHEN 'ョ' THEN
                ret := 'ョ';
            -- その他 伸ばし棒ー(マイナスとは違う)
            WHEN 'ー' THEN
                ret := 'ー';
            -- アルファベット
            -- 小文字
            WHEN 'a' THEN
                ret := 'a';
            WHEN 'b' THEN
                ret := 'b';
            WHEN 'c' THEN
                ret := 'c';
            WHEN 'd' THEN
                ret := 'd';
            WHEN 'e' THEN
                ret := 'e';
            WHEN 'f' THEN
                ret := 'f';
            WHEN 'g' THEN
                ret := 'g';
            WHEN 'h' THEN
                ret := 'h';
            WHEN 'i' THEN
                ret := 'i';
            WHEN 'j' THEN
                ret := 'j';
            WHEN 'k' THEN
                ret := 'k';
            WHEN 'l' THEN
                ret := 'l';
            WHEN 'm' THEN
                ret := 'm';
            WHEN 'n' THEN
                ret := 'n';
            WHEN 'o' THEN
                ret := 'o';
            WHEN 'p' THEN
                ret := 'p';
            WHEN 'q' THEN
                ret := 'q';
            WHEN 'r' THEN
                ret := 'r';
            WHEN 's' THEN
                ret := 's';
            WHEN 't' THEN
                ret := 't';
            WHEN 'u' THEN
                ret := 'u';
            WHEN 'v' THEN
                ret := 'v';
            WHEN 'w' THEN
                ret := 'w';
            WHEN 'x' THEN
                ret := 'x';
            WHEN 'y' THEN
                ret := 'y';
            WHEN 'z' THEN
                ret := 'z';
            -- 大文字
            WHEN 'A' THEN
                ret := 'A';
            WHEN 'B' THEN
                ret := 'B';
            WHEN 'C' THEN
                ret := 'C';
            WHEN 'D' THEN
                ret := 'D';
            WHEN 'E' THEN
                ret := 'E';
            WHEN 'F' THEN
                ret := 'F';
            WHEN 'G' THEN
                ret := 'G';
            WHEN 'H' THEN
                ret := 'H';
            WHEN 'I' THEN
                ret := 'I';
            WHEN 'J' THEN
                ret := 'J';
            WHEN 'K' THEN
                ret := 'K';
            WHEN 'L' THEN
                ret := 'L';
            WHEN 'M' THEN
                ret := 'M';
            WHEN 'N' THEN
                ret := 'N';
            WHEN 'O' THEN
                ret := 'O';
            WHEN 'P' THEN
                ret := 'P';
            WHEN 'Q' THEN
                ret := 'Q';
            WHEN 'R' THEN
                ret := 'R';
            WHEN 'S' THEN
                ret := 'S';
            WHEN 'T' THEN
                ret := 'T';
            WHEN 'U' THEN
                ret := 'U';
            WHEN 'V' THEN
                ret := 'V';
            WHEN 'W' THEN
                ret := 'W';
            WHEN 'X' THEN
                ret := 'X';
            WHEN 'Y' THEN
                ret := 'Y';
            WHEN 'Z' THEN
                ret := 'Z';
            -- 数字
            WHEN '0' THEN
                ret := '0';
            WHEN '1' THEN
                ret := '1';
            WHEN '2' THEN
                ret := '2';
            WHEN '3' THEN
                ret := '3';
            WHEN '4' THEN
                ret := '4';
            WHEN '5' THEN
                ret := '5';
            WHEN '6' THEN
                ret := '6';
            WHEN '7' THEN
                ret := '7';
            WHEN '8' THEN
                ret := '8';
            WHEN '9' THEN
                ret := '9';
            ELSE
                -- 定義されていないものはそのまま返す
                ret := c;
        END CASE;
        RETURN ret;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE;
    
    -- 全角文字列を半角文字列に変更する関数。
    CREATE FUNCTION zenkaku2hankakukana_string (str TEXT)
    RETURNS TEXT AS $$
    DECLARE
        ret TEXT;
        i INTEGER := 1;
        -- 何文字取るか
        cap INTEGER := 1;
    BEGIN
    
        WHILE i <= char_length(str)
        LOOP
            ret := concat(ret, zenkaku2hankakukana(SUBSTRING(str, i, cap)));
            -- 取った数だけ進める
            i := i + cap;
        END LOOP;
    
        RETURN ret;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE;
    
    
    -- 半角を全角に変更する
    CREATE FUNCTION hankakukana2zenkaku (c VARCHAR(2))
    RETURNS CHAR(1) AS $$
    DECLARE
        ret CHAR(1);
    BEGIN
    
        CASE c
            -- ア行
            WHEN 'ア' THEN
                ret := 'ア';
            WHEN 'イ' THEN
                ret := 'イ';
            WHEN 'ウ' THEN
                ret := 'ウ';
            WHEN 'エ' THEN
                ret := 'エ';
            WHEN 'オ' THEN
                ret := 'オ';
            -- カ行
            WHEN 'カ' THEN
                ret := 'カ';
            WHEN 'キ' THEN
                ret := 'キ';
            WHEN 'ク' THEN
                ret := 'ク';
            WHEN 'ケ' THEN
                ret := 'ケ';
            WHEN 'コ' THEN
                ret := 'コ';
            -- サ行
            WHEN 'サ' THEN
                ret := 'サ';
            WHEN 'シ' THEN
                ret := 'シ';
            WHEN 'ス' THEN
                ret := 'ス';
            WHEN 'セ' THEN
                ret := 'セ';
            WHEN 'ソ' THEN
                ret := 'ソ';
            -- タ行
            WHEN 'タ' THEN
                ret := 'タ';
            WHEN 'チ' THEN
                ret := 'チ';
            WHEN 'ツ' THEN
                ret := 'ツ';
            WHEN 'テ' THEN
                ret := 'テ';
            WHEN 'ト' THEN
                ret := 'ト';
            -- ナ行
            WHEN 'ナ' THEN
                ret := 'ナ';
            WHEN 'ニ' THEN
                ret := 'ニ';
            WHEN 'ヌ' THEN
                ret := 'ヌ';
            WHEN 'ネ' THEN
                ret := 'ネ';
            WHEN 'ノ' THEN
                ret := 'ノ';
            -- ハ行
            WHEN 'ハ' THEN
                ret := 'ハ';
            WHEN 'ヒ' THEN
                ret := 'ヒ';
            WHEN 'フ' THEN
                ret := 'フ';
            WHEN 'ヘ' THEN
                ret := 'ヘ';
            WHEN 'ホ' THEN
                ret := 'ホ';
            -- マ行
            WHEN 'マ' THEN
                ret := 'マ';
            WHEN 'ミ' THEN
                ret := 'ミ';
            WHEN 'ム' THEN
                ret := 'ム';
            WHEN 'メ' THEN
                ret := 'メ';
            WHEN 'モ' THEN
                ret := 'モ';
            -- ヤ行
            WHEN 'ヤ' THEN
                ret := 'ヤ';
            WHEN 'ユ' THEN
                ret := 'ユ';
            WHEN 'ヨ' THEN
                ret := 'ヨ';
            -- ワ行
            WHEN 'ワ' THEN
                ret := 'ワ';
            WHEN 'ヲ' THEN
                ret := 'ヲ';
            WHEN 'ン' THEN
                ret := 'ン';
            -- ガ行
            WHEN 'ガ' THEN
                ret := 'ガ';
            WHEN 'ギ' THEN
                ret := 'ギ';
            WHEN 'グ' THEN
                ret := 'グ';
            WHEN 'ゲ' THEN
                ret := 'ゲ';
            WHEN 'ゴ' THEN
                ret := 'ゴ';
            -- ザ行
            WHEN 'ザ' THEN
                ret := 'ザ';
            WHEN 'ジ' THEN
                ret := 'ジ';
            WHEN 'ズ' THEN
                ret := 'ズ';
            WHEN 'ゼ' THEN
                ret := 'ゼ';
            WHEN 'ゾ' THEN
                ret := 'ゾ';
            -- ダ行
            WHEN 'ダ' THEN
                ret := 'ダ';
            WHEN 'ヂ' THEN
                ret := 'ヂ';
            WHEN 'ヅ' THEN
                ret := 'ヅ';
            WHEN 'デ' THEN
                ret := 'デ';
            WHEN 'ド' THEN
                ret := 'ド';
            -- バ行
            WHEN 'バ' THEN
                ret := 'バ';
            WHEN 'ビ' THEN
                ret := 'ビ';
            WHEN 'ブ' THEN
                ret := 'ブ';
            WHEN 'ベ' THEN
                ret := 'ベ';
            WHEN 'ボ' THEN
                ret := 'ボ';
            -- パ行
            WHEN 'パ' THEN
                ret := 'パ';
            WHEN 'ピ' THEN
                ret := 'ピ';
            WHEN 'プ' THEN
                ret := 'プ';
            WHEN 'ペ' THEN
                ret := 'ペ';
            WHEN 'ポ' THEN
                ret := 'ポ';
            -- 小文字
            WHEN 'ァ' THEN
                ret := 'ァ';
            WHEN 'ィ' THEN
                ret := 'ィ';
            WHEN 'ゥ' THEN
                ret := 'ゥ';
            WHEN 'ェ' THEN
                ret := 'ェ';
            WHEN 'ォ' THEN
                ret := 'ォ';
            WHEN 'ッ' THEN
                ret := 'ッ';
            WHEN 'ャ' THEN
                ret := 'ャ';
            WHEN 'ュ' THEN
                ret := 'ュ';
            WHEN 'ョ' THEN
                ret := 'ョ';
            -- その他 伸ばし棒-(マイナス)とは違う
            WHEN 'ー' THEN
                ret := 'ー';
            -- アルファベット
            -- 小文字
            WHEN 'a' THEN
                ret := 'a';
            WHEN 'b' THEN
                ret := 'b';
            WHEN 'c' THEN
                ret := 'c';
            WHEN 'd' THEN
                ret := 'd';
            WHEN 'e' THEN
                ret := 'e';
            WHEN 'f' THEN
                ret := 'f';
            WHEN 'g' THEN
                ret := 'g';
            WHEN 'h' THEN
                ret := 'h';
            WHEN 'i' THEN
                ret := 'i';
            WHEN 'j' THEN
                ret := 'j';
            WHEN 'k' THEN
                ret := 'k';
            WHEN 'l' THEN
                ret := 'l';
            WHEN 'm' THEN
                ret := 'm';
            WHEN 'n' THEN
                ret := 'n';
            WHEN 'o' THEN
                ret := 'o';
            WHEN 'p' THEN
                ret := 'p';
            WHEN 'q' THEN
                ret := 'q';
            WHEN 'r' THEN
                ret := 'r';
            WHEN 's' THEN
                ret := 's';
            WHEN 't' THEN
                ret := 't';
            WHEN 'u' THEN
                ret := 'u';
            WHEN 'v' THEN
                ret := 'v';
            WHEN 'w' THEN
                ret := 'w';
            WHEN 'x' THEN
                ret := 'x';
            WHEN 'y' THEN
                ret := 'y';
            WHEN 'z' THEN
                ret := 'z';
            -- 大文字
            WHEN 'A' THEN
                ret := 'A';
            WHEN 'B' THEN
                ret := 'B';
            WHEN 'C' THEN
                ret := 'C';
            WHEN 'D' THEN
                ret := 'D';
            WHEN 'E' THEN
                ret := 'E';
            WHEN 'F' THEN
                ret := 'F';
            WHEN 'G' THEN
                ret := 'G';
            WHEN 'H' THEN
                ret := 'H';
            WHEN 'I' THEN
                ret := 'I';
            WHEN 'J' THEN
                ret := 'J';
            WHEN 'K' THEN
                ret := 'K';
            WHEN 'L' THEN
                ret := 'L';
            WHEN 'M' THEN
                ret := 'M';
            WHEN 'N' THEN
                ret := 'N';
            WHEN 'O' THEN
                ret := 'O';
            WHEN 'P' THEN
                ret := 'P';
            WHEN 'Q' THEN
                ret := 'Q';
            WHEN 'R' THEN
                ret := 'R';
            WHEN 'S' THEN
                ret := 'S';
            WHEN 'T' THEN
                ret := 'T';
            WHEN 'U' THEN
                ret := 'U';
            WHEN 'V' THEN
                ret := 'V';
            WHEN 'W' THEN
                ret := 'W';
            WHEN 'X' THEN
                ret := 'X';
            WHEN 'Y' THEN
                ret := 'Y';
            WHEN 'Z' THEN
                ret := 'Z';
            -- 数字
            WHEN '0' THEN
                ret := '0';
            WHEN '1' THEN
                ret := '1';
            WHEN '2' THEN
                ret := '2';
            WHEN '3' THEN
                ret := '3';
            WHEN '4' THEN
                ret := '4';
            WHEN '5' THEN
                ret := '5';
            WHEN '6' THEN
                ret := '6';
            WHEN '7' THEN
                ret := '7';
            WHEN '8' THEN
                ret := '8';
            WHEN '9' THEN
                ret := '9';
            ELSE
                -- 定義されていないものはそのまま返す
                ret := c;
        END CASE;
        RETURN ret;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE;
    
    -- 合字(二つで一つの文字か判定)
    CREATE FUNCTION ligature (c VARCHAR(2))
    RETURNS BOOLEAN AS $$
    DECLARE
        ret BOOLEAN := FALSE;
    BEGIN
        -- 2文字の時のみ
        IF char_length(c) = 2 THEN
            -- 濁音、 半濁音は他の音があって初めてなので
            -- 実際あるか同時は他の関数に委ねる。漫画などにある表現として「あ」の濁点とかがあるので。
            IF Substring(c, 2, 1) IN ('゙', '゚') THEN
                ret := TRUE;
            END IF;
            -- 2文字以上の合字が出たら足して行く。
        -- 3文字以上の合字が出たらELSE IF で追加して行く。
        END IF;
    
        RETURN ret;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE;
    
    -- 半角文字列を全角文字列に変更する関数。
    CREATE FUNCTION hankakukana2zenkaku_string (str TEXT)
    RETURNS TEXT AS $$
    DECLARE
        ret TEXT;
        i INTEGER := 1;
        -- 何文字取るか
        cap INTEGER := 1;
    BEGIN
    
        WHILE i <= char_length(str)
        LOOP
            -- 合字かどうか。
            -- 指定の位置から最大二文字取る。
            IF ligature(SUBSTRING(str, i, 2)) THEN
                -- 2文字で一つの文字なので二文字取る。
                cap := 2;
            ELSE
                cap := 1; 
            END IF;
                ret := concat(ret, hankakukana2zenkaku(SUBSTRING(str, i, cap)));
                -- 取った数だけ進める
                i := i + cap;
        END LOOP;
    
        RETURN ret;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE;
    

    사용법


    first_name, secound_만약name에 전각 문자열이 있다면
    반각 문자열은 잘 출력됩니다.
    SELECT
    secound_name
    ,zenkaku2hankakukana_string(secound_name) AS secound_name_kana
    ,first_name
    ,zenkaku2hankakukana_string(first_name) AS first_name_kana
    FROM users
    
    도 다음 그림과 같이 생성 열에 포함할 수 있습니다.
    CREATE TABLE users (
        id SERIAL NOT NULL,
        secound_name varchar(20),
        secound_name_kana varchar(20) GENERATED ALWAYS AS (zenkaku2hankakukana_string(secound_name)) STORED
        first_name varchar(20),
        first_name_kana varchar(20) GENERATED ALWAYS AS (zenkaku2hankakukana_string(first_name)) STORED
    );
    

    최신 소스 코드


    github에 있어요.
    github

    좋은 웹페이지 즐겨찾기