我有一个Web服务,它从NCLOB列中提取文本并通过XML返回数据。 NCLOB列通过从文档中提取文本来填充,因此有时会在XML中放置无效的XML字符,从而导致使用系统失败。
作为per the 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') || ']',' ')
我们怎样才能匹配高代理人?任何想法或指导都会非常感激。
答案 0 :(得分: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,这是一个带clob>的示例32k字符:
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
答案 1 :(得分: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ö