我有一个列,其中包含我想要转义的数据,以便将其用作JSON输出,更准确地说,我试图逃避此处列出的相同字符,但使用的是Oracle 11g:Special Characters and JSON Escaping Rules
我认为可以使用REGEXP_REPLACE来解决:
SELECT REGEXP_REPLACE(my_column, '("|\\|/)|(' || CHR(9) || ')', '\\\1') FROM my_table;
但我很遗憾更换其他字符(制表符,新行,退格键等),在前面的例子中我知道\ 1将匹配并替换第一组但我不知道如何捕获选项卡第二组然后用\ t替换它。有人可以给我一个关于如何更换的暗示吗?
我知道我可以这样做:
SELECT REGEXP_REPLACE( REGEXP_REPLACE(my_column, '("|\\|/)', '\\\1'), '(' || CHR(9) || ')', '\t')
FROM my_table;
但是我必须像对REGEXP_REPLACE的5次调用一样嵌套,我怀疑我应该能够在一两次调用中完成它。
我知道JSON的其他软件包或库,但我认为这种情况很简单,可以通过Oracle提供的开箱即用功能来解决。
谢谢。
答案 0 :(得分:3)
这是一个开始。替换所有常规字符很容易,它是控制字符将是棘手的。此方法使用由字符类组成的组,该字符类包含要在前面添加反斜杠的字符。请注意,类中的字符不需要转义。 REGEXP_REPLACE为1的参数表示从第一个位置开始,0表示替换在源字符串中找到的所有匹配项。
SELECT REGEXP_REPLACE('t/h"is"'||chr(9)||'is a|te\st', '([/\|"])', '\\\1', 1, 0) FROM dual;
通过将上面的内容包装在REPLACE调用中,可以很容易地替换TAB和回车符,但是它必须为每个控制字符执行此操作。因此,我担心我的答案对你来说并不是一个完整的答案,它只能帮助你解决一些常规字符:
SQL> SELECT REPLACE(REPLACE(REGEXP_REPLACE('t/h"is"'||chr(9)||'is
2 a|te\st', '([/\|"])', '\\\1', 1, 0), chr(9), '\t'), chr(10), '\n') fixe
3 FROM dual;
FIXED
-------------------------
t\/h\"is\"\tis\na\|te\\st
SQL>
编辑:这是一个解决方案!我没有声称完全理解它,但基本上它创建了一个连接到您的字符串的转换表(在inp_str表中)。 connect by,level遍历字符串的长度,并替换转换表中匹配的字符。我在这里修改了一个解决方案:http://database.developer-works.com/article/14901746/Replace+%28translate%29+one+char+to+many真的没有很好的解释。希望有人在这里充实并完整解释。
SQL> with trans_tbl(ch_frm, str_to) as (
select '"', '\"' from dual union
select '/', '\/' from dual union
select '\', '\\' from dual union
select chr(8), '\b' from dual union -- BS
select chr(12), '\f' from dual union -- FF
select chr(10), '\n' from dual union -- NL
select chr(13), '\r' from dual union -- CR
select chr(9), '\t' from dual -- HT
),
inp_str as (
select 'No' || chr(12) || 'w is ' || chr(9) || 'the "time" for /all go\od men to '||
chr(8)||'com' || chr(10) || 'e to the aid of their ' || chr(13) || 'country' txt from dual
)
select max(replace(sys_connect_by_path(ch,'`'),'`')) as txt
from (
select lvl
,decode(str_to,null,substr(txt, lvl, 1),str_to) as ch
from inp_str cross join (select level lvl from inp_str connect by level <= length(txt))
left outer join trans_tbl on (ch_frm = substr(txt, lvl, 1))
)
connect by lvl = prior lvl+1
start with lvl = 1;
TXT
------------------------------------------------------------------------------------------
No\fw is \tthe \"time\" for \/all go\\od men to \bcom\ne to the aid of their \rcountry
SQL>
编辑8/10/2016 - 使其成为封装和可重用性的功能,以便您可以同时将其用于多个列:
create or replace function esc_json(string_in varchar2)
return varchar2
is
s_converted varchar2(4000);
BEGIN
with trans_tbl(ch_frm, str_to) as (
select '"', '\"' from dual union
select '/', '\/' from dual union
select '\', '\\' from dual union
select chr(8), '\b' from dual union -- BS
select chr(12), '\f' from dual union -- FF
select chr(10), '\n' from dual union -- NL
select chr(13), '\r' from dual union -- CR
select chr(9), '\t' from dual -- HT
),
inp_str(txt) as (
select string_in from dual
)
select max(replace(sys_connect_by_path(ch,'`'),'`')) as c_text
into s_converted
from (
select lvl
,decode(str_to,null,substr(txt, lvl, 1),str_to) as ch
from inp_str cross join (select level lvl from inp_str connect by level <= length(txt))
left outer join trans_tbl on (ch_frm = substr(txt, lvl, 1))
)
connect by lvl = prior lvl+1
start with lvl = 1;
return s_converted;
end esc_json;
一次调用多个列的示例:
select esc_json(column_1), esc_json(column_2)
from your_table;
答案 1 :(得分:1)
受上面答案的启发,我创造了这个更简单的&#34; one-liner&#34;功能:
create or replace function json_esc (
str IN varchar2
) return varchar2
begin
return REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(str, chr(8), '\b'), chr(9), '\t'), chr(10), '\n'), chr(12), '\f'), chr(13), '\r');
end;
请注意,上面的这个和@Gary_W的答案都没有转义所有控制字符,因为json.org似乎表明了这一点。
答案 2 :(得分:0)
在sql server中,您可以使用STRING_ESCAPE()函数,如下所示:
data-vv-as