如何检测字符串中的非 ASCII 字符?

Posted

技术标签:

【中文标题】如何检测字符串中的非 ASCII 字符?【英文标题】:How do I detect non-ASCII characters in a string? 【发布时间】:2011-06-27 19:09:31 【问题描述】:

如果我有一个 php 字符串,我如何以一种有效的方式确定它是否包含至少一个非 ASCII 字符?非 ASCII 字符是指不属于此表的任何字符,http://www.asciitable.com/,位置 32 - 126(含)。

所以它不仅必须是 ASCII 表的一部分,而且还必须是可打印的。我想检测一个字符串,其中至少包含一个不符合这些规范的字符(不可打印的 ASCII 或完全不同的字符,例如不属于该表的 Unicode 字符。

【问题讨论】:

所以你的意思不是Unicode,而是非US-ASCII?如果您正在寻找有效的东西,我认为这是值得指定的。 你能对字符串做出任何安全的假设吗,比如编码? 所有 ASCII 字符都是 也是 UTF-8 字符)。 添加了说明。抱歉之前的歧义。 类似于***.com/questions/4147646/… 【参考方案1】:

我发现检测是否有任何字符不在列表中更有用

if(preg_match('/[^\x20-\x7e]/', $string))

【讨论】:

记住 0x7F 是删除字符,所以它需要是 '/[^\x20-\x7e]/' 因为 0x7e 是 ~,所以这在技术上并不准确。 这个答案很好,但是你可以在这篇帖子***.com/questions/4147646/…中找到更多的解决方案 @wheresrhys 我认为您的 sn-ps 测试字符串中的所有字符是否都是 ascii,对于任何字符代码都应该是 /[^\x20-\x7f]/.test(theString) @Karolis,我允许自己编辑您的答案:正如@simontemplar 6 年前在评论中正确指出的那样,7F (DEL) 不是可打印的 ASCII 字符。此外,OP 明确要求“32-126 inclusive”,翻译为20-7E。这个问题已经看了几千次了,你的回答是公认的,不要误导人!【参考方案2】:

您可以使用mb_detect_encoding 并检查 ASCII:

mb_detect_encoding($str, 'ASCII', true)

如果$str 包含至少一个非ASCI 字符(字节值> 0x7F),这将返回false

【讨论】:

mb_check_encoding 更合适:mb_check_encoding($str, 'ASCII')【参考方案3】:

试试 (mb_detect_encoding)

【讨论】:

【参考方案4】:

如果所有字符都落在 ASCII 范围 32-126 (PHP unit test) 内,则函数 ctype_print 返回 true。

【讨论】:

php -r 'echo ctype_print("\xa0");' 打印出1 所以这个函数有问题。 @forthrin:我无法确认。对我来说,php -r 'var_dump(ctype_print("\xa0"));' 返回 false(使用 PHP 7.0.10)。 我也在 PHP 7.0.10 上,Homebrew 版本 (OS X)。会不会是终端、语言环境、php.ini 或其他环境因素造成的差异? 对我也不起作用,Windows 上的 PHP 7.0.5 - 不知道为什么。它似乎不再起作用了。我们可能应该打开一个错误报告?【参考方案5】:

我对建议的函数进行了基准测试,因为我需要对较短(最多 1000 个字符)字符串的批处理进行检查。我测试了 30 个不同字符串的 10k 次迭代(空、短、长、ascii、重音符号、日语、表情符号、非 ascii 开始、非 ascii 结束等)。以下是粗略的结果:

mb_check_encoding:平均 95 毫秒。随着字符串变长 (1MB+),性能下降的速度比 preg_match 和 ctype 快。

mb_check_encoding($input, 'ASCII');

preg_match:平均 85 毫秒。对于 1MB+ 的字符串来说速度相当快(遍历字符串,如果字符串的前面有非 ascii 字符,速度会更快)。

!preg_match('/[\\x80-\\xff]/', $input);

ctype_print:平均 83 毫秒。对于 1MB+ 的字符串来说速度相当快(遍历字符串,如果字符串早期有非 ascii 字符,速度会更快)。 请注意,这并不是真正的 ascii 检查

ctype_print($input);

while/ord:平均 500 毫秒。我仍在等待 1MB+ 字符串测试完成。

function is_ascii($input) 
    $num = 0;
    while( isset( $string[$num] ) ) 
        if( ord( $string[$num] ) & 0x80 ) 
            return false;
        
        $num++;
    
    return true;

【讨论】:

【参考方案6】:

你可以使用:

mb_detect_encoding

但它可能不会像您希望的那样精确。

【讨论】:

【参考方案7】:

试试:(Source)

function is_ascii( $string = '' ) 
    return ( bool ) ! preg_match( '/[\\x80-\\xff]+/' , $string );

尽管上述所有答案都是正确的,但根据输入的不同,这些解决方案可能会给出错误的答案。请参阅this ASCII validation post 的最后一节。

【讨论】:

【参考方案8】:

我建议你查看 PHP 手册中的 utf8_encode 或 utf8_decode:

http://www.php.net/manual/en/function.utf8-encode.php

查看下面的示例,因为如果没有找到您正在寻找的东西,它可能会引导您走向正确的方向。

【讨论】:

【参考方案9】:

如果你不想在javascript中处理Regex,你可以这样做

detectUf8 : function(s) 
  var utf8=s.split('').filter(function(C) 
    return C.charCodeAt(0)>127;
  )
  return (utf8.join('').length>0);
,

【讨论】:

这个问题是关于 PHP 而不是 JavaScript。

以上是关于如何检测字符串中的非 ASCII 字符?的主要内容,如果未能解决你的问题,请参考以下文章

处理 textField:shouldChangeCharactersInRange:replacementString: 中的非 ascii 字符

SyntaxError:函数返回“£”时文件中的非 ASCII 字符“\xa3”

如何检测列表中的非数字? [复制]

Python NLTK:SyntaxError:文件中的非 ASCII 字符“\xc3”(情绪分析-NLP)

带有加扰的非 ASCII 字符的 JSONP 字符串

识别和替换括号之间的非 ASCII 字符