2017-10-18 64 views
0

我有一个FUNCTION,它用一个单独的水平空间替换STRING中的多个(连续)水平空间;Oracle - 字符串 - 标点符号格式化函数

例如

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. 

*注意:当在闭括号后面直接出现逗号或完全停止符时,而不是'One HORIZONTAL SPACE'规则,它将使用'No HORIZONTAL SPACE'规则。

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

非常感谢提前。

回答

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; 
/
+0

这是一流的@Kaushik Nayak!我真的很感激你花时间工作 - 非常感谢。 – MAndrews

1

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

注意:该函数不考虑出现在同一个字符串中的多种类型的模式。所以如果“,”和“。”都出现,它将不起作用。因此,您可以自己编写所有需要的转换代码,EXCEPTION来处理这些情况。我已经给出了关于如何完成的想法。您可能需要重写IF THENCASE块,因为我在代码为PL/SQL的with子句中编码。

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; 
/
+0

真棒,谢谢,Kaushik Nayak - 我会尽快测试。非常感激。 – MAndrews

+0

不幸的是,这个编译好,但经过测试,它会导致'ORA-01422:精确的读取返回超过请求的行数'。张贴之前进行测试 - 多好的概念! :-) – mathguy

+0

@mathguy:是的!我提醒用户关于考虑我在这里的时间.. –