従来の理由により、Oracle 10データベースにはVARCHAR2列があり(文字エンコードがAL32UTF8
に設定されています)、UTF-8以外の値が含まれています。値は常に次のいずれかの文字セットです。
データベースの外で壊れた値を修正するPerl関数を作成しました。このデータベース列の値の場合、このエンコードのリストをループして、値をUTF-8に変換しようとします。変換が失敗した場合、次のエンコーディングを試みます。エラーなしで変換する最初のものが、保持する値です。さて、この機能をデータベース内に複製して、誰でも使用できるようにしたいと思います。
ただし、これについて私が見つけることができるのは CONVERT
function だけです。これは失敗することはありませんが、認識できない文字の代わりの文字を挿入します。したがって、私が知る限り、変換がいつ失敗したかを知る方法はありません。
そのため、2つの質問があります。
UPDATE:
参考までに、私はこのPostgreSQL関数をPL/pgSQLで記述しました。
CREATE OR REPLACE FUNCTION encoding_utf8(
bytea
) RETURNS TEXT LANGUAGE PLPGSQL STRICT IMMUTABLE AS $$
DECLARE
encoding TEXT;
BEGIN
FOREACH encoding IN ARRAY ARRAY[
'UTF8',
'WIN1252',
'LATIN1'
] LOOP
BEGIN
RETURN convert_from($1, encoding);
EXCEPTION WHEN character_not_in_repertoire OR untranslatable_character THEN
CONTINUE;
END;
END LOOP;
END;
$$;
Oracleで同等の方法を実行する方法を知りたいと思います。
@collapsarからのUTF-8の不正な文字に関する重要な情報と、同僚によるいくつかの掘り下げのおかげで、私はこれを思い付きました:
CREATE OR REPLACE FUNCTION reencode(string IN VARCHAR2) RETURN VARCHAR2
AS
encoded VARCHAR2(32767);
type array_t IS varray(3) OF VARCHAR2(15);
array array_t := array_t('AL32UTF8', 'WE8MSWIN1252', 'WE8ISO8859P1');
BEGIN
FOR I IN 1..array.count LOOP
encoded := CASE array(i)
WHEN 'AL32UTF8' THEN string
ELSE CONVERT(string, 'AL32UTF8', array(i))
END;
IF instr(
rawtohex(
utl_raw.cast_to_raw(
utl_i18n.raw_to_char(utl_raw.cast_to_raw(encoded), 'utf8')
)
),
'EFBFBD'
) = 0 THEN
RETURN encoded;
END IF;
END LOOP;
RAISE VALUE_ERROR;
END;
奇妙なことに、それはWE8ISO8859P1には決して到達しません。WE8MSWIN1252は、私が苦情なく持っている800程度の悪い値のリストのすべてを変換します。同じことは、私のPerlまたはPostgreSQL実装にも当てはまりません。CP1252は一部の値で失敗しますが、ISO-8859-1は成功します。それでも、Oracleの値は適切で、有効なUnicode(PostgreSQLにロードすることによってテストされた)のように見えるため、文句を言うことはできません。これは私のデータを消毒するのに十分だと思います。
データベース列に無効なutf-8が含まれているかどうかを確認するには、次のクエリを使用します。
select CASE
INSTR (
RAWTOHEX (
utl_raw.cast_to_raw (
utl_i18n.raw_to_char (
utl_raw.cast_to_raw ( <your_column> )
, 'utf8'
)
)
)
, 'EFBFBD'
)
WHEN 0 THEN 'OK'
ELSE 'FAIL'
END
from <your_table>
;
あなたのdb文字セットがal32utf8であると仮定します。
ご了承ください EF BF BD
は tf-8での不正なエンコード を表します。
指定する他のすべての文字セットはバイト指向であるため、Unicodeへの変換が失敗することはありませんが、異なるコードポイントが生成される可能性があります。コンテキスト情報がないと、実際のソース文字セットを自動決定することはできません。
よろしく、carsten
ps:Oracleの文字セットの名前:CP1252
-> WE8MSWIN1252
LATIN-1
-> WE8ISO8859P1