转义JSON输出的特殊字符

时间:2015-11-25 03:45:07

标签: sql json regex oracle

我有一个列,其中包含我想要转义的数据,以便将其用作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提供的开箱即用功能来解决。

谢谢。

3 个答案:

答案 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