找出一个字符串是不是只包含 ASCII 字符

Posted

技术标签:

【中文标题】找出一个字符串是不是只包含 ASCII 字符【英文标题】:Find out if a string contains only ASCII characters找出一个字符串是否只包含 ASCII 字符 【发布时间】:2018-11-27 14:55:51 【问题描述】:

我需要知道一个字符串是否只包含 ASCII 字符。到目前为止,我使用这个正则表达式:

DECLARE
    str VARCHAR2(100) := 'xyz';
BEGIN
    IF REGEXP_LIKE(str, '^[ -~]+$') THEN
        DBMS_OUTPUT.PUT_LINE('Pure ASCII');
    END IF;
END;
/

Pure ASCII

' '~ 分别是第一个。 ASCII 中的最后一个字符。

问题是,此 REGEXP_LIKE 在某些 NLS 设置上失败:

ALTER SESSION SET NLS_SORT = 'GERMAN'; 

DECLARE
    str VARCHAR2(100) := 'xyz';
BEGIN
    IF REGEXP_LIKE(str, '^[ -~]+$') THEN
        DBMS_OUTPUT.PUT_LINE('Pure ASCII');
    END IF;
END;
/

ORA-12728: invalid range in regular expression
ORA-06512: at line 4

有人知道独立于当前用户 NLS 设置的解决方案吗?这种行为是故意的还是应该被视为错误?

【问题讨论】:

这个能用吗:IF (ASCIISTR(str) = str) THEN? [ -~] 是可打印的 ascii,但 ascii 确实是 7 位 [\x00-\x7F] 有趣的是,反斜杠似乎未能通过该测试; asciistr('\') 给出\005C,大概是为了避免混淆,因为它在输出中具有特殊含义。 @sln, [\x20-\x7E] 也会引发 ORA-12728 @sln - 在 Oracle 的德语语言排序顺序中,字符 x20 比字符 x7E“更大”。 x7E 是#63,x20 是#66。完整的可打印 ASCII 字符范围是 x21 - x39。 【参考方案1】:

您可以使用TRANSLATE 来执行此操作。基本上,translate 去掉所有 ASCII 可打印字符(没有那么多),看看你还剩下什么。

这是一个执行此操作的查询:

WITH input ( p_string_to_test) AS ( 
SELECT 'This this string' FROM DUAL UNION ALL
SELECT 'Test this ' || CHR(7) || ' string too!' FROM DUAL UNION ALL
SELECT 'xxx' FROM DUAL)
SELECT p_string_to_test, 
       case when translate(p_string_to_test, 
       chr(0) || q'[ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~]', 
       chr(0)) is null then 'Yes' else 'No' END is_ascii
FROM input;
+-------------------------+----------+
|    P_STRING_TO_TEST     | IS_ASCII |
+-------------------------+----------+
| This this string        | Yes      |
| Test this  string too!  | No       |
| xxx                     | Yes      |
+-------------------------+----------+

【讨论】:

[:print:] 包括非 ascii 字符。【参考方案2】:

可以使用上限为127ASCII函数:

declare
    str nvarchar2(100) := '\xyz~*-=)(/&%+$#£>|"éß';
    a   nvarchar2(1);
    b   number := 0;
begin
    for i in 1..length(str)
    loop                 
      a := substrc(str,i,1);
      b := greatest(ascii(a),b);      
    end loop;

    if b < 128 then  
     dbms_output.put_line('String is composed of Pure ASCII characters');
    else
     dbms_output.put_line('String has non-ASCII characters');      
    end if; 
end;

【讨论】:

【参考方案3】:

我想我会选择这两个中的一个

IF CONVERT(str, 'US7ASCII') = str THEN
    DBMS_OUTPUT.PUT_LINE('Pure ASCII');
END IF;



IF ASCIISTR(REPLACE(str, '\', '/')) = REPLACE(str, '\', '/') THEN
    DBMS_OUTPUT.PUT_LINE('Pure ASCII');
END IF;

【讨论】:

那些将包括范围低端的不可打印字符,不是吗? @MatthewMcPeak,是的,但我的主要兴趣是找到像 öäü 这样的特殊字符。不可打印的字符与我的情况无关。

以上是关于找出一个字符串是不是只包含 ASCII 字符的主要内容,如果未能解决你的问题,请参考以下文章

仅包含 ASCII 字符的 UNICODE 字符串是不是总是等于 ASCII 字符串?

找出一个只出现一次的字符

如何在 Linux 中打开包含非 Ascii 字符串的 wchar_t* 文件?

如何判断字符串中是不是包含任何非 ASCII 字符?

剑指 Offer 50. 第一个只出现一次的字符

如何在 C# 中获取字符串的 ASCII 值