【问题标题】:Oracle - String - Punctuation Formatting FunctionOracle - 字符串 - 标点格式化功能
【发布时间】:2017-10-18 16:22:10
【问题描述】:

我有一个FUNCTION,它用单个水平空间替换STRING 中的多个(连续)水平空间;

例如

STR_ORIG = 'Hello    World'
STR_NEW  = 'Hello World'

函数如下;

CREATE OR REPLACE FUNCTION CP_RDN_PUNCT(
  INS VARCHAR2)
 RETURN VARCHAR2
AS
 OUTSTR VARCHAR2(4000);
 STR VARCHAR2(4000);
BEGIN
 STR := INS;
 WHILE (INSTR(STR,' ',1) > 0 )
 LOOP
  OUTSTR := OUTSTR || ' ' || SUBSTR(STR,1,INSTR(STR,' ',1) - 1);
  STR := TRIM(BOTH ' ' FROM SUBSTR(STR,INSTR(STR,' ',1)));
 END LOOP;
OUTSTR := OUTSTR || ' ' || TRIM(STR);
RETURN TRIM(OUTSTR);
END CP_RDN_PUNCT;

但是,我想扩展这个 FUNCTION,以便它能够更正基本的标点格式(逗号、句号和括号)。但是,重要的是 FUNCTION 继续删除多个(连续的)水平空间。

例如;

如果STR_ORIG = 'Hello , Marc' 输出将变为'Hello, Marc'

如果STR_ORIG = 'Hello.Marc' 输出将变为'Hello. Marc'

如果STR_ORIG = 'Hello(Marc )' 输出将变为'Hello (Marc)'

我想使用的规则是相当基本的:

Comma;...............One HORIZONTAL SPACE after a Comma.
                     No HORIZONTAL SPACE before a Comma.

Full Stop;...........One HORIZONTAL SPACE after a Full Stop.
                     No HORIZONTAL SPACE before a Full Stop.

Open Parenthesis;....No HORIZONTAL SPACE after an Open Parenthesis.
                     One HORIZONTAL SPACE before an Open Parenthesis.

Closed Parenthesis;..One HORIZONTAL SPACE after an Closed Parenthesis*.          
                     No HORIZONTAL SPACE before an Closed Parenthesis.

*注意:如果逗号或句号直接出现在右括号之后,而不是“一个HORIZONTAL SPACE”规则,它将使用“否HORIZONTAL SPACE”规则。

我相信FUNCTION 是解决此问题的最佳方法(我曾探索过使用纯 SQL (REG_EXP),但代码开始变得非常混乱 - 主要是由于数据不一致)。此外,如果我想在将来添加其他规则(例如下划线规则),我假设 FUNCTION 会更容易维护。不过,我一如既往地愿意听取专业人士的建议。

非常感谢。

【问题讨论】:

    标签: string oracle function plsql punctuation


    【解决方案1】:

    我能想到的另一种方法是使用associated array 来存储模式和替换而不是普通的sql。然后在循环中对字符串应用每个转换。

    CREATE OR REPLACE FUNCTION cp_rdn_punct2 (
        inp_pattern VARCHAR2
    ) RETURN VARCHAR2 AS
    
        v_outstr   VARCHAR2(1000) := inp_pattern;
        TYPE v_astype IS
            TABLE OF VARCHAR2(40) INDEX BY VARCHAR(40);
        v_pat      v_astype;
        v_idx      VARCHAR2(40);
    
    BEGIN
        v_pat(' *, *' ) := ', ';
        v_pat(' *\. *') := '. ';
        v_pat(' *\( *') := ' (';
        v_pat(' *\) *') := ') ';
        v_idx := v_pat.first;
        WHILE v_idx IS NOT NULL LOOP
            v_outstr := regexp_replace(v_outstr,v_idx,v_pat(v_idx) );
            v_idx := v_pat.next(v_idx);
        END LOOP;
    
        RETURN v_outstr;
    END;
    /
    

    【讨论】:

    • 这太棒了,@Kaushik Nayak!非常感谢您抽出时间来解决这个问题 - 非常感谢。
    【解决方案2】:

    您可以使用REGEXP 编写函数,而不是使用INSTR、SUBSTR。

    注意:此函数不考虑同一字符串中出现的多种模式。因此,如果“,”和“。”都出现,它将不起作用。因此,您可以自己编写所有需要的转换代码、EXCEPTION 处理等来涵盖这些场景。我已经给了你关于如何做到这一点的想法。您可能必须使用 IF THEN 或 CASE 块重写,因为我在 with 子句中为类似 PL/SQL 的代码编写代码。

    CREATE OR REPLACE FUNCTION CP_RDN_PUNCT(
      inp_pattern VARCHAR2)
     RETURN VARCHAR2
    AS 
    outstr VARCHAR2(4000);
    BEGIN
    with reg  ( pattern, regex ,replacement ) AS
    
    (
        select ',' , ' *, *', ', ' FROM DUAL  UNION ALL
        select '.' , ' *\. *', '. ' FROM DUAL UNION ALL
        select '(' , ' *\( *', ' (' FROM DUAL 
      )
     SELECT
        TRIM(regexp_replace(rep,' *\) *',') ') ) INTO outstr
    FROM
        (
            SELECT
                regexp_replace(inp_pattern,regex,replacement) rep
            FROM
                reg
            WHERE
                inp_pattern LIKE '%'
                || pattern
                || '%'
        );
    
    RETURN outstr;
    
    END;
    /
    

    【讨论】:

    • 太棒了,谢谢,Kaushik Nayak - 我很快就会测试。非常感谢。
    • 不幸的是,这编译正常,但经过测试,结果为ORA-01422: exact fetch returns more than requested number of rows。发布前进行测试 - 多么棒的概念! :-)
    猜你喜欢
    • 2013-03-24
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    相关资源
    最近更新 更多