【问题标题】:Multiple REPLACE function in OracleOracle中的多个REPLACE函数
【发布时间】:2010-06-01 06:18:24
【问题描述】:

我在 oracle 中使用 REPLACE 函数来替换我的字符串中的值,例如;

 SELECT REPLACE('THE NEW VALUE IS #VAL1#','#VAL1#','55') from dual

所以这可以替换一个值,但是20+呢,我应该使用20+REPLACE函数还是有更实际的解决方案。

欢迎所有想法。

【问题讨论】:

    标签: oracle replace


    【解决方案1】:

    即使这个线程是旧的,也是谷歌上的第一个,所以我将发布一个与这里实现的函数等效的 Oracle,使用正则表达式。

    比嵌套的 replace() 快得多,而且更简洁。

    在给定表的字符串列中将字符串 'a','b','c' 替换为 'd'

    select regexp_replace(string_col,'a|b|c','d') from given_table
    

    它只不过是几个带有“或”运算符的静态模式的正则表达式。

    小心正则表达式的特殊字符!

    【讨论】:

    • 这个简单的解决方案比编写自己的函数来做已经实现的事情要好得多。
    • 我同意这是关于实际问题的更好答案
    • 好多了!非常感谢!
    • 这会将abc中的任何一个替换为d,但大概要求是用单独的值替换每个值以允许从模板构建字符串例如'No #VAL1# exists for this #VAL2#' 传递 ('vendor', 'cheese type')。不过,我同意这个问题并不是特别清楚。
    • 如果你想替换 \n、\t、\r 之类的东西,你必须这样做:REGEXP_REPLACE(column, '\x09|\x0A|\x0D','') as column - 最后是两个单引号..
    【解决方案2】:

    how to replace multiple strings together in Oracle 的公认答案建议使用嵌套的 REPLACE 语句,我认为没有更好的方法。

    如果你打算大量使用它,你可以考虑编写自己的函数:

    CREATE TYPE t_text IS TABLE OF VARCHAR2(256);
    
    CREATE FUNCTION multiple_replace(
      in_text IN VARCHAR2, in_old IN t_text, in_new IN t_text
    )
      RETURN VARCHAR2
    AS
      v_result VARCHAR2(32767);
    BEGIN
      IF( in_old.COUNT <> in_new.COUNT ) THEN
        RETURN in_text;
      END IF;
      v_result := in_text;
      FOR i IN 1 .. in_old.COUNT LOOP
        v_result := REPLACE( v_result, in_old(i), in_new(i) );
      END LOOP;
      RETURN v_result;
    END;
    

    然后像这样使用它:

    SELECT multiple_replace( 'This is #VAL1# with some #VAL2# to #VAL3#',
                             NEW t_text( '#VAL1#', '#VAL2#', '#VAL3#' ),
                             NEW t_text( 'text', 'tokens', 'replace' )
                           )
    FROM dual
    

    这是带有一些要替换的标记的文本

    如果您的所有标记都具有相同的格式 ('#VAL' || i || '#'),您可以省略参数 in_old 并改用您的循环计数器。

    【讨论】:

    • @Adnan:不客气,但我会等待一段时间才能接受我的答案 - 可能还有其他/更好的答案:)
    • RETURN VARCHAR2 DETERMINISTIC 可能会更快。
    【解决方案3】:

    记住后果

    SELECT REPLACE(REPLACE('TEST123','123','456'),'45','89') FROM DUAL;
    

    将123替换为456,然后发现可以将45替换为89。 对于具有等效结果的函数,它必须复制优先级(即以相同的顺序替换字符串)。

    类似地,获取一个字符串“ABCDEF”,并指示它用“123”替换“ABC”,用“xyz”替换“CDE”,仍然需要考虑优先级来确定它是转到“123EF”还是ABxyzF'。

    简而言之,很难想出任何比嵌套 REPLACE 更简单的通用方法(尽管更像 sprintf 风格的函数会是一个有用的补充)。

    【讨论】:

      【解决方案4】:

      如果您的所有源字符串和替换字符串都只有一个字符长,您可以简单地使用TRANSLATE 函数:

        SELECT translate('THIS IS UPPERCASE', 'THISUP', 'thisup') 
        FROM DUAL
      

      详情请见the Oracle documentation

      【讨论】:

        【解决方案5】:

        这是一篇旧帖子,但我最终使用了 Peter Lang 的想法,并采用了类似但不同的方法。这是我所做的:

        CREATE OR REPLACE FUNCTION multi_replace(
                                pString IN VARCHAR2
                                ,pReplacePattern IN VARCHAR2
        ) RETURN VARCHAR2 IS
            iCount  INTEGER;
            vResult VARCHAR2(1000);
            vRule   VARCHAR2(100);
            vOldStr VARCHAR2(50);
            vNewStr VARCHAR2(50);
        BEGIN
            iCount := 0;
            vResult := pString;
            LOOP
                iCount := iCount + 1;
        
                -- Step # 1: Pick out the replacement rules
                vRule := REGEXP_SUBSTR(pReplacePattern, '[^/]+', 1, iCount);
        
                -- Step # 2: Pick out the old and new string from the rule
                vOldStr := REGEXP_SUBSTR(vRule, '[^=]+', 1, 1);
                vNewStr := REGEXP_SUBSTR(vRule, '[^=]+', 1, 2);
        
                -- Step # 3: Do the replacement
                vResult := REPLACE(vResult, vOldStr, vNewStr);
        
                EXIT WHEN vRule IS NULL;
            END LOOP;
        
            RETURN vResult;
        END multi_replace;
        

        然后我可以这样使用它:

        SELECT  multi_replace(
                                'This is a test string with a #, a $ character, and finally a & character'
                                ,'#=%23/$=%24/&=%25'
                )
        FROM dual
        

        这样我就可以使用任何字符/字符串来处理任何字符/字符串。

        我在我的博客上写了一篇关于这个的帖子。

        【讨论】:

          【解决方案6】:

          我通过一个 varchar2 表作为参数创建了一个通用的多替换字符串 Oracle 函数。 varchar 将被替换为 table 的位置 rownum 值。

          例如:

          Text: Hello {0}, this is a {2} for {1}
          Parameters: TABLE('world','all','message')
          

          返回:

          Hello world, this is a message for all.
          

          你必须创建一个类型:

          CREATE OR REPLACE TYPE "TBL_VARCHAR2" IS TABLE OF VARCHAR2(250);
          

          函数是:

          CREATE OR REPLACE FUNCTION FN_REPLACETEXT(
              pText IN VARCHAR2, 
              pPar IN TBL_VARCHAR2
          ) RETURN VARCHAR2
          IS
              vText VARCHAR2(32767);
              vPos INT;
              vValue VARCHAR2(250);
          
              CURSOR cuParameter(POS INT) IS
              SELECT VAL
                  FROM
                      (
                      SELECT VAL, ROWNUM AS RN 
                      FROM (
                            SELECT COLUMN_VALUE VAL
                            FROM TABLE(pPar)
                            )
                      )
                  WHERE RN=POS+1;
          BEGIN
              vText := pText;
              FOR i IN 1..REGEXP_COUNT(pText, '[{][0-9]+[}]') LOOP
                  vPos := TO_NUMBER(SUBSTR(REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i),2, LENGTH(REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i)) - 2));
          
                  OPEN cuParameter(vPos);
                  FETCH cuParameter INTO vValue;
                  IF cuParameter%FOUND THEN
                      vText := REPLACE(vText, REGEXP_SUBSTR(pText, '[{][0-9]+[}]',1,i), vValue);
                  END IF;
                  CLOSE cuParameter;
              END LOOP;
          
              RETURN vText;
          
          EXCEPTION
                WHEN OTHERS
                THEN
                   RETURN pText;
          END FN_REPLACETEXT;
          /
          

          用法:

          TEXT_RETURNED := FN_REPLACETEXT('Hello {0}, this is a {2} for {1}', TBL_VARCHAR2('world','all','message'));
          

          【讨论】:

            【解决方案7】:

            感谢您的回答。除了在调用中指定翻译,您还可以使用光标来执行此操作,如下所示。

            create or replace function character_substitutions (input_str varchar2)
            return varchar2
            
            as
            
            v_result VARCHAR2(4000);
            
            cursor c_translate_table is
                select '&' as symbol_to_replace, 'amp' as symbol_in_return_string from dual
                union all
                select '/' as symbol_to_replace, '_' as symbol_in_return_string from dual
                union all
                select '"' as symbol_to_replace, 'in' as symbol_in_return_string from dual
                union all
                select '%' as symbol_to_replace, 'per' as symbol_in_return_string from dual
                union all
                select '.' as symbol_to_replace, '_' as symbol_in_return_string from dual;
                
            begin
            
            v_result := input_str;
            
            for r_translate in c_translate_table loop
            
                v_result := REPLACE( v_result, r_translate.symbol_to_replace, r_translate.symbol_in_return_string);
            
            end loop;
            
            return v_result;
            
            end;
            /
            

            【讨论】:

              【解决方案8】:

              另一个如何应用有序字符替换列表的示例。在这种情况下:

              • 将反斜杠转换为斜杠
              • 将出现的双斜杠转换为单斜杠
              • 将单引号转换为转义单引号

              例如,转换自:

              \\server\Folder\611891\Joe's Doc.pdf

              /server/Folder/611891/Joe\'s Doc.pdf

              可以使用递归 CTE 依次遍历有序列表。第一部分演示字符串如何演变:

              WITH subs AS (
                       SELECT '\' convert_from, '/' convert_to, 1 seq FROM DUAL
                 UNION SELECT '//',  '/',   2     FROM DUAL
                 UNION SELECT '''',  '\''', 3     FROM DUAL
              ),
              
              rcte(convert_from, convert_to, seq, src) AS (
                SELECT '', '', 0, '\\server\Folder\611891\Joe''s Doc.pdf' src FROM DUAL
                UNION ALL
                SELECT s.convert_from, s.convert_to, s.seq, REPLACE(r.src, s.convert_from, s.convert_to)
                  FROM rcte r
                  JOIN subs s ON (s.seq = r.seq + 1)
              )
              
              SELECT *
                FROM rcte
                ORDER BY seq
              ; 
              
              | CONVERT_FROM | CONVERT_TO | SEQ |                                  SRC |
              |--------------|------------|-----|--------------------------------------|
              |       (null) |     (null) |   0 | \\server\Folder\611891\Joe's Doc.pdf |
              |            \ |          / |   1 | //server/Folder/611891/Joe's Doc.pdf |
              |           // |          / |   2 |  /server/Folder/611891/Joe's Doc.pdf |
              |            ' |         \' |   3 | /server/Folder/611891/Joe\'s Doc.pdf |
              

              但实际上只对最终结果感兴趣:

              SELECT src
                FROM rcte
                WHERE seq = (SELECT MAX(seq) FROM subs)
              ;
              
              |                                  SRC |
              |--------------------------------------|
              | /server/Folder/611891/Joe\'s Doc.pdf |
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-04-13
                • 1970-01-01
                • 1970-01-01
                • 2021-08-02
                • 2022-07-14
                • 1970-01-01
                相关资源
                最近更新 更多