4

NCLOB 列からテキストを取得し、XML 経由でデータを返す Web サービスがあります。NCLOB 列は、ドキュメントからテキストを抽出することによって入力されるため、無効な XML 文字が XML に配置され、消費システムが失敗する場合があります。

W3Cによると、有効な文字の範囲は次のとおりです。

#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
/* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

私たちはいくつかの異なる RegExp パターンを試しましたが、それに近づいていますが、まだ完全には到達していません。ここが一番近いところです。上位サロゲート (DB9B - DBFF) を除いて、すべての無効な文字が置き換えられます。

REGEXP_REPLACE(
    TEXT,
    '[^[:print:]' || chr(13) || chr(10) || ']|[' || UNISTR('\FFFE-\FFFF') || ']',
    '*')

これも試しましたが、サロゲート (D800 - DFFE) はどれも置き換えられません。

REGEXP_REPLACE(REPLACE(TEXT, unistr('\0000'), ' '),
      '[' || unistr('\0001-\0008') || ']' 
  || '|[' || unistr('\000B-\000C') || ']'
  || '|[' || unistr('\000E-\001F') || ']'
  || '|[' || unistr('\D800-\DFFF') || ']' 
  || '|[' || unistr('\FFFE-\FFFF') || ']',' ')

上位のサロゲートをどのように一致させることができますか? ご意見やご指導をいただければ幸いです。

4

2 に答える 2

2

regex_replace高いサロゲートでは機能しないように見えるので、独自の関数を作成できます。次に例を示します(9.2および11.2でテスト済み)。

CREATE OR REPLACE FUNCTION replace_invalid(p_clob NCLOB) RETURN NCLOB IS
   l_result NCLOB;
   l_char   NVARCHAR2(1 char);
BEGIN
   FOR i IN 1 .. length(p_clob) LOOP
      l_char := substr(p_clob, i, 1);
      IF utl_raw.cast_to_binary_integer(utl_raw.cast_to_raw(l_char)) 
          BETWEEN to_number('DB9B', 'xxxx') AND to_number('DBFF', 'xxxx') THEN
         l_result := l_result || N'*';
      ELSE
         l_result := l_result || l_char;
      END IF;
   END LOOP;
   RETURN l_result;
END;

大きなNCLOBで実行する必要があります。これは、32k文字を超えるclobの例です。

SQL> DECLARE
  2     l_in  NCLOB;
  3     l_out NCLOB;
  4  BEGIN
  5     FOR i IN 1 .. to_number('DBFF', 'xxxx') LOOP
  6        l_in := l_in || nchr(i);
  7     END LOOP;
  8     dbms_output.put_line('l_in length:' || length(l_in));
  9     l_out := replace_invalid(l_in);
 10     dbms_output.put_line('l_out length:' || length(l_out));
 11     dbms_output.put_line('chars replaced:' 
 12                        || (length(l_out) - length(REPLACE(l_out, '*', ''))));
 13  END;
 14  /

l_in length:56319
l_out length:56319
chars replaced:102
于 2013-01-18T09:02:59.253 に答える
0

一連の呼び出し TRANSLATE を使用できます。例えば、

SELECT UNISTR('abc\00e5\00f1\00f6') Source FROM DUAL;
SELECT TRANSLATE(UNISTR('abc\00e5\00f1\00f6'), UNISTR('a\00e5\00f1'), 'a') Final FROM DUAL;

Source
------
abcåñö

Final
------
abcö

SQLフィドル

于 2013-01-18T09:06:33.407 に答える