Oracle - 字符串 - 标点符号格式化函数

Oracle - String - Punctuation Formatting Function

我有一个 FUNCTIONSTRING 中的多个(连续)水平 Space 替换为单个水平 Space;

例如

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 继续删除多个(连续的)水平 Spaces.

例如;

如果 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.

*注意:当逗号或句号直接出现在右括号之后时,它将使用 'No HORIZONTAL SPACE' 规则而不是 'One HORIZONTAL SPACE' 规则。

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

非常感谢。

您可以使用 REGEXP 编写函数,而不是使用 INSTRSUBSTR

注意:此函数不考虑同一字符串中出现的多种模式。因此,如果“,”和“。”都出现,它将不起作用。因此,您可以自己编写所有需要的转换代码,EXCEPTION 处理等来涵盖此类场景。我已经给了你关于如何完成的想法。您可能需要用 IF THENCASE 块重写,因为我在 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;
/

我能想到的另一种方法是使用 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;
/