PHP - 仅包含ASCII扩展字符的字符串

4
使用PHP,我想知道我的$字符串中是否包含此列表中33到255之间的任何非ASCII-扩展字符:http://www.ascii-code.com/。同时,是否可能包括其他各种ASCII字符以进行拒绝?比如182和135(分别是¶和‡符号)。我的意思是,如果$string中有这些符号,我也希望得到一个布尔值false。
我知道如何在ASCII中完成这个操作,但不知道如何在ASCII-Extended中完成。

ASCII中的48代表数字0,为什么它被称为非ASCII扩展字符 - anubhava
3个回答

3

扩展ASCII码在十进制128-255之间,而普通(7位)ASCII可打印字符为32(空格)至126(波浪号)。

因此,用于查找任何超出正常可打印范围的8位字符的正则表达式将是:

/[^ -~]/

基本上,这意味着“不包括空格到波浪号”。在PHP中:
$nonprintable_or_extended = preg_match('/[^ -~]/', $string) === 1;

编辑后添加: 我重新阅读了你的问题,并且经过思考,我认为你也希望允许一些“扩展ASCII”字符。对于这个问题没有简单的答案,因为任何超过代码点127的字符都涉及到字符编码。在美国,我们通常使用以下三种之一:

  1. ISO-8859-1定义了Latin-1字符集,并允许在128-255范围内使用e-grave、e-acute等字符,但有一些空缺(http://en.wikipedia.org/wiki/Iso_8859-1)。
  2. cp1252(或Windows Codepage 1252)基本上与ISO-8859-1相同,只是它在129-159范围内添加了更多的字符,而ISO-8859-1则保留了这些未分配的字符(http://en.wikipedia.org/wiki/Cp1252)。
  3. UTF-(8, 16, 32)字符串使用高阶ASCII字符集来寻址整个Unicode光谱(65535及以上),因此要想知道“什么是有效的可打印字符?”,需要更多的思考。

根据下面的评论进行编辑:如果您想允许某些字符,请先标准化输入编码。我们将使用UTF-8进行操作,可以检查和转换cp1252/ISO-8859-1的编码:

// Validate the UTF-8 (from drupal_validate_utf8()).
// @see https://api.drupal.org/api/drupal/includes!bootstrap.inc/function/drupal_validate_utf8/7
if (strlen($string) != 0 && preg_match('/^./us', $string) !== 1) {
  // Convert to UTF-8 if it isn't already (assuming input was "Western" cp1252/ISO).
  $string = @iconv('Windows-1252', 'UTF-8//IGNORE', $string);
}

现在$string已经保证是一个有效的UTF-8编码字符串。然后,为了只允许单字节的“扩展ASCII”(Latin-1和cp1252提供的补充),并以区域设置感知的方式转换类似的字符:
// Ensure the locale is right for our iconv() operations.
// This establishes how transliteration will determine the appropriate destination character(s).
setlocale(LC_CTYPE, 'en_US.UTF-8');
$string = iconv('utf-8', 'CP1252//TRANSLIT//IGNORE', $string);

在这一点上,$string将是一个cp1252的单字节表示字符串;任何超出该范围的内容都将被转换(如果可能)或丢弃。您可以使用正则表达式进一步进行过滤,例如:
// Allow only printable characters (exclude control codes below \x20 [space char]),
// and only the Euro cp1252 character (\x80) and A-tilde (Ãã) characters (\xC3 and \xE3).
$filtered_string = preg_replace('[\x20-\x7F\x80\xC3\xE3]+', '', $string);

我刚刚创建了一个test.php文件,其中包含以下内容: <?php $string = '例子'; $nonprintable_or_extended = preg_match('/[^ -~]/', $string) === 1; echo $nonprintable_or_extended ? 'FAIL' : 'PASS'; ?> 当我将文件存储为UTF-8(无BOM)时,它可以正常工作,这是由于UTF-8的工作方式。否则,由于这些中文字符需要多字节编码,任何其他编码都会导致Unicode编码问题。 - Jay Dansand
尝试使用 € 符号 (虽然它是扩展的 ASCII 字符) 。我仍在收集有关您建议的这两种字符编码的信息。顺便说一句,感谢您的帮助。 - Jack M.
请记住,在不知道字符串编码的情况下,这非常脆弱。正则表达式可能更好地写成/ [^ -~\x80] /,使用转义序列来表示欧元符号,因为它在cp1252中是有效的。这仅适用于cp1252。如果欧元符号以UTF-8形式输入,则为字节0xE2 0x82 0xAC,或者在UTF-16中可以是0x20 0xAC或0xAC 0x20(取决于字节顺序等),等等。 - Jay Dansand
到目前为止,我正在使用以下代码:preg_match('/^([\x00-\x7F€])*$/', $string) - Jack M.
1
答案完全取决于输入编码。因此,我假设它是作为ISO-8859-1/cp1252(现代浏览器共同称之为“西方”)传入的,并且我们可以使用单个代码\x80(欧元符号)、\xC3(大写Ã)和\xE3(小写ã)。我还将使用preg_replace()编写它,因为ereg_replace()已被弃用。$filtered_string = preg_replace('[\x00-\x7F\x80\xC3\xE3]+', '', $string) - Jay Dansand
显示剩余4条评论

1

编辑:请查看这个工作演示

从!到ÿ

检查是否有任何字符不在ASCII范围33到255内非常容易。只需使用此正则表达式:

`[^!-ÿ]`

这是一个否定字符类,匹配在“!”和“ÿ”之间出现的任何字符。请注意,扩展ASCII范围取决于机器的语言环境。它应该对您有用。 还要排除 为了排除这些字符,我们可以将初始的否定类分成三个范围,以便为两个新字符腾出空间:从“!”到“ˆ”的前一个字符...... 从“ˆ”的后一个字符到“¶”的前一个字符...... 从“¶”后面的字符到“ÿ”。但是,将这两个字符添加到自己的类中并使用OR连接更加简洁(且易于维护)。您可以使用以下正则表达式:
`[ˆ¶]|[^!-ÿ]`
  • 如果在[ˆ¶]中找到两个字符中的任意一个,或者找到|,则表示匹配成功。
  • 如果字符不在!-ÿ范围内,则也表示匹配成功。

要添加排除内容,只需将字符添加到第一个类别中即可。


所有这些都返回相同的结果:$string = 'asд€!$da:‰sdFf3Ff3 '; $string = 'abc'; $string = 'д€'; echo preg_match('/[^!-ÿ]/','', $string); - Jack M.
@JackM。你的第二个参数为空,应该是字符串。你把它反了。:) 请查看演示 - zx81
抱歉,我有些困惑,因为我正在尝试将此转换为 ereg replace,以便可以摆脱所有非扩展 ASCII 字符。 - Jack M.
警告:一旦允许126以上的字节值,您就进入了字符编码的世界,因此您首先需要修复输入。通过允许33-255(!-ÿ)的字节值,您允许所有UTF-8,此时您实际上在限制可允许的字符方面没有做任何有用的事情。字节0xFF(255)仅在ISO-8859-1 /等中为ÿ。这个笑脸:☺只是三个字节“☺”(0xE2 0x98 0xBA),但网站告诉您的浏览器应该使用UTF-8将它们显示为单个字符,而不是在ISO-8859-1中作为3个字符显示。阅读我的答案以获取更多信息。 - Jay Dansand

0

检测扩展ASCII字符集可以使用以下方法:

$extended = preg_match('/[\x7f-\xff]/', $str );

它运行良好。对于中文字符,它返回“true”,但对于常规ASCII字符,则返回“false”。 - anubhava
是的,但€符号甚至'ã'都无法通过 :( - Jack M.
你确定你使用正确吗?使用 返回 true 而不加 (只用 ASCII)返回 false - anubhava
[\x7f-\xff] 是扩展 ASCII 的范围。 - anubhava
我不知道为什么变量$extended甚至不起作用:解析错误:语法错误,意外的“var”(T_VAR)。 - Jack M.
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接