Oracle-Regex用0.00替换([0-9] {1,} \。[0-9] {1,}),但不能用<qcom> </qcom>包围

时间:2018-10-31 01:15:29

标签: sql regex oracle oracle11g

我必须替换XML标记内的值以使值零

示例:

<cProd>7898132541927</cProd>
<cEAN>7898132541927</cEAN>
<uCom>UN</uCom>
<qCom>12.0000</qCom>
<vUnCom>47.6600000000</vUnCom>
<vProd>571.92</vProd>
<cEANTrib>7898132541927</cEANTrib>
<uTrib>UN</uTrib>
<qTrib>12.0000</qTrib>
<vUnTrib>47.6600000000</vUnTrib>
<indTot>1</indTot>

我需要的结果:

<cProd>7898132541927</cProd>
<cEAN>7898132541927</cEAN>
<uCom>UN</uCom>
<qCom>12.0000</qCom>
<vUnCom>0.00</vUnCom>
<vProd>0.00</vProd>
<cEANTrib>7898132541927</cEANTrib>
<uTrib>UN</uTrib>
<qTrib>12.0000</qTrib>
<vUnTrib>0.00</vUnTrib>
<indTot>1</indTot>

我必须使用Oracle,然后才能编写正确的脚本:

SELECT
REGEXP_REPLACE('
    <cProd>7898132541927</cProd>
    <cEAN>7898132541927</cEAN>
    <uCom>UN</uCom>
    <qCom>12.0000</qCom>
    <vUnCom>47.6600000000</vUnCom>
    <vProd>571.92</vProd>
    <cEANTrib>7898132541927</cEANTrib>
    <uTrib>UN</uTrib>
    <qTrib>12.0000</qTrib>
    <vUnTrib>47.6600000000</vUnTrib>
    <indTot>1</indTot>
'
, '([0-9]{1,}\.[0-9]{1,})(?!</qCom|?!</qTrib)'
, '0.00') RES
FROM DUAL
;

正则表达式([0-9]{1,}\.[0-9]{1,})可以工作,但是在标签qComqTrib中,我必须在正则表达式中做一个例外

有人可以提供帮助。 Tks

2 个答案:

答案 0 :(得分:1)

我无法使它与负向后方((?<!))一起使用,但我注意到您唯一要设置为0.00的数字是那些以v开头的标记内的数字。 / p>

使用正则表达式((?<=),此正则表达式模式似乎有效:

'(?<=<v[A-Za-z]+>)([0-9]+\.[0-9]+)'

在您提供的示例中使用,将会产生

<cProd>7898132541927</cProd>
<cEAN>7898132541927</cEAN>
<uCom>UN</uCom>
<qCom>12.0000</qCom>
<vUnCom>0.00</vUnCom>
<vProd>0.00</vProd>
<cEANTrib>7898132541927</cEANTrib>
<uTrib>UN</uTrib>
<qTrib>12.0000</qTrib>
<vUnTrib>0.00</vUnTrib>
<indTot>1</indTot>

正则表达式详细信息:

'(?<='           Assert that the regex below can be matched, with the match ending at this position (positive lookbehind)
   '<v'          Match the characters “<v” literally
   '[A-Za-z]'    Match a single character present in the list below
                 A character in the range between “A” and “Z”
                 A character in the range between “a” and “z”
      '+'        Between one and unlimited times, as many times as possible, giving back as needed (greedy)
   '>'           Match the character “>” literally
')' 
'('              Match the regular expression below and capture its match into backreference number 1
   '[0-9]'       Match a single character in the range between “0” and “9”
      '+'        Between one and unlimited times, as many times as possible, giving back as needed (greedy)
   '\.'          Match the character “.” literally
   '[0-9]'       Match a single character in the range between “0” and “9”
      '+'        Between one and unlimited times, as many times as possible, giving back as needed (greedy)
')' 

答案 1 :(得分:0)

鉴于Oracle已经具有内置的XML功能来执行此操作-为什么不使用该功能?

例如XQuery更新(假定有效的XML文档)

WITH table_name (xmlvalue)
     AS (SELECT XMLTYPE (
'<Document>
  <cProd>7898132541927</cProd>
  <cEAN>7898132541927</cEAN>
  <uCom>UN</uCom>
  <qCom>12.0000</qCom>
  <vUnCom>47.6600000000</vUnCom>
  <vProd>571.92</vProd>
  <cEANTrib>7898132541927</cEANTrib>
  <uTrib>UN</uTrib>
  <qTrib>12.0000</qTrib>
  <vUnTrib>47.6600000000</vUnTrib>
  <indTot>1</indTot>
</Document>') FROM DUAL)
SELECT XMLQUERY (
         'copy $new := $old 
          modify (
             for $node in $new/Document/node()[matches(.,"[0-9]+\.[0-9]+") and not(local-name()=("qCom","qTrib"))] 
             return replace value of node $node with "0.00") 
          return $new'
          PASSING 
             xmlvalue AS "old"
          RETURNING CONTENT) result
FROM   table_name;

<Document>
  <cProd>7898132541927</cProd>
  <cEAN>7898132541927</cEAN>
  <uCom>UN</uCom>
  <qCom>12.0000</qCom>
  <vUnCom>0.00</vUnCom>
  <vProd>0.00</vProd>
  <cEANTrib>7898132541927</cEANTrib>
  <uTrib>UN</uTrib>
  <qTrib>12.0000</qTrib>
  <vUnTrib>0.00</vUnTrib>
  <indTot>1</indTot>
</Document>