如何在Oracle中使用regexp_replace在两个字符串之间提取值?

时间:2015-07-27 11:33:57

标签: regex oracle plsql

我想替换Oracle中REGEXP_REPLACE中找到的值。我使用regex101.com工具来调试我的正则表达式,它也突出了结果,但是如果我将这个表达式放入我的select中,它什么都不做......它不会替换我想要的字符串。所以,我的问题是,为什么这种模式在Oracle PL / SQL中是错误的?

select REGEXP_REPLACE('SOME XML DATAS', '/(?<=</FIRST_TAG>)(.*)(?=</LAST_TAG>)/s', '<REPLACE_TAG xsi:nil="1"/>') from dual

如您所见,我在两个结束标签之间进行搜索。

示例XML:

<?xml version='1.0' encoding='UTF-8'?>
<LAST_TAG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:bla-bla-bla">
 <DEFAULT_LANGUAGE>en</DEFAULT_LANGUAGE>
 <DEBUG>0</DEBUG>
 <DEBUG_LEVEL>MEDIUM</DEBUG_LEVEL>
 <DEBUG_FILE>bla-bla.log</DEBUG_FILE>
 <FIRST_TAG>
  <LOGICAL_PRINTER>
   <ID>PRINTER1</ID>
   <PHYSICAL_PRINTER>Dummy_Printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT01</ID>
   <PHYSICAL_PRINTER>PRINT01</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT012</ID>
   <PHYSICAL_PRINTER>PRINT02</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT015</ID>
   <PHYSICAL_PRINTER>PRINT05</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT019</ID>
   <PHYSICAL_PRINTER>PRINT019</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT010</ID>
   <PHYSICAL_PRINTER>PRINT010</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID01</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT011</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID03</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT013</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID04</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT014</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID05</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT015</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>BUDCOLOR</ID>
   <PHYSICAL_PRINTER>\\url\printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>NAMENAME</ID>
   <PHYSICAL_PRINTER>\\url\printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
 </FIRST_TAG>
 <LOCALE_LIST>
  <LOCALE>
   <DISPLAY_NAME>English (United States)</DISPLAY_NAME>
   <COUNTRY>US</COUNTRY>
   <LANGUAGE>en</LANGUAGE>
   <VARIANT xsi:nil="1"/>
  </LOCALE>
 </LOCALE_LIST>
</LAST_TAG>

非常感谢!

2 个答案:

答案 0 :(得分:2)

精细手册的相关部分:Using Regular Expressions in Database Applications

我们的想法是匹配要替换的文本周围的文本,并使用反向引用来匹配替换字符串中的子表达式

with data(id, str) as (
  select 1, 'foo is bar' from dual union all
  select 2, 'foo was bar' from dual union all
  select 3, 'foo might be or might not be bar' from dual
)
select 
 id
,str
,regexp_replace(str, '^(foo).+(bar)$', '\1***\2') as str2
from data
;

OP示例数据的另一个示例。请注意使用match parameter n

  

'n'允许句点(。)(匹配任意字符)匹配换行符。如果省略此参数,则句点与换行符不匹配。

该参数是必需的,因为该字符串包含换行符号。以下示例将正确消除LOCALE_LIST - 元素。 警告:请注意,建议您不要使用正则表达式操作字符串化XML。

with data(id, str) as (
  select 1, q'[<?xml version='1.0' encoding='UTF-8'?>
<LAST_TAG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:bla-bla-bla">
 <DEFAULT_LANGUAGE>en</DEFAULT_LANGUAGE>
 <FIRST_TAG>
  <LOGICAL_PRINTER>
   <ID>PRINTER1</ID>
   <PHYSICAL_PRINTER>Dummy_Printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
 </FIRST_TAG>
 <LOCALE_LIST>
  <LOCALE>
   <DISPLAY_NAME>English (United States)</DISPLAY_NAME>
   <VARIANT xsi:nil="1"/>
  </LOCALE>
 </LOCALE_LIST>
</LAST_TAG>]' from dual
)
select 
 id
,regexp_replace(str, '(.+</FIRST_TAG>).+(</LAST_TAG>)', '\1***\2', 1, 1, 'n') as str2
from data
;

答案 1 :(得分:0)

也许您尝试像xmldocument一样处理xml而不是像文本一样。

declare 
 v xmltype:= xmltype('<?xml version=''1.0'' encoding=''UTF-8''?>
<LAST_TAG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <DEFAULT_LANGUAGE>en</DEFAULT_LANGUAGE>
 <DEBUG>0</DEBUG>
 <DEBUG_LEVEL>MEDIUM</DEBUG_LEVEL>
 <DEBUG_FILE>bla-bla.log</DEBUG_FILE>
 <FIRST_TAG>
  <LOGICAL_PRINTER>
   <ID>PRINTER1</ID>
   <PHYSICAL_PRINTER>Dummy_Printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT01</ID>
   <PHYSICAL_PRINTER>PRINT01</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT012</ID>
   <PHYSICAL_PRINTER>PRINT02</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT015</ID>
   <PHYSICAL_PRINTER>PRINT05</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT019</ID>
   <PHYSICAL_PRINTER>PRINT019</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT010</ID>
   <PHYSICAL_PRINTER>PRINT010</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID01</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT011</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID03</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT013</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID04</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT014</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>PRINT_ID05</ID>
   <PHYSICAL_PRINTER>\\111.111.111.111\PRINT015</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>BUDCOLOR</ID>
   <PHYSICAL_PRINTER>\\url\printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
  <LOGICAL_PRINTER>
   <ID>NAMENAME</ID>
   <PHYSICAL_PRINTER>\\url\printer</PHYSICAL_PRINTER>
  </LOGICAL_PRINTER>
 </FIRST_TAG>
 <LOCALE_LIST>
  <LOCALE>
   <DISPLAY_NAME>English (United States)</DISPLAY_NAME>
   <COUNTRY>US</COUNTRY>
   <LANGUAGE>en</LANGUAGE>
   <VARIANT xsi:nil="1"/>
  </LOCALE>
 </LOCALE_LIST>
</LAST_TAG>');
begin 
 v := v.deleteXML('/LAST_TAG/DEBUG_FILE/following-sibling::*','xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"').appendChildXML('/LAST_TAG',xmltype('<NEW_TAG/>'));
 dbms_output.put_line(v.getClobVal());
end;