从字符串中删除非ASCII字符

124
var str="INFO] :谷���新道, ひば���ヶ丘2丁���, ひばりヶ���, 東久留米市 (Higashikurume)";

我需要从字符串中移除所有非ASCII字符,这意味着字符串只包含"INFO] (Higashikurume)"。

6个回答

319

ASCII的范围在0到127之间,所以:

str.replace(/[^\x00-\x7F]/g, "");

10
搜索 ASCII 表 - 你会发现只有值从零到一百二十七的字符是有效的(0x7F 在十六进制中是 127)。这段代码匹配所有不在 ASCII 范围内的字符并将它们移除。 - Zaffy
1
谢谢分享。您介意解释一下 \x7F 如何工作吗?再次感谢。 - Daniel
2
@eyyo II代表最后一个ASCII字符。我无法在此类注释中给您完整的解释。它被称为十六进制转义序列,如果您搜索它,您肯定会找到大量关于它的信息。 - Zaffy
如果您能编辑您的答案并提供更多关于它如何工作的信息,那将非常棒。现在它并没有真正帮助我理解。 - Robin Métral

47

也可以通过肯定的删除断言来完成,方法如下:

textContent = textContent.replace(/[\u{0080}-\u{FFFF}]/gu,"");

使用了Unicode。在JavaScript中,当表示正则表达式的Unicode时,字符是用转义序列\u{xxxx}指定的,但是还必须有标志'u'; 请注意,正则表达式具有标志'gu'

我将其称为“积极断言性的删除”,因为“积极”断言表达要删除哪些字符,而“否定”断言表达要保留哪些字符。在许多上下文中,如先前答案所述,否定断言可能更具启示性。插入符号"^"表示“不”,范围\x00-\x7F表示“ASCII”,所以两者组合起来表示“非ASCII”。

textContent = textContent.replace(/[^\x00-\x7F]/g,"");

对于仅关心英语的英语使用者来说,这是一个很好的解决方案,也是原问题的一个不错的答案。 但在更一般的情况下,我们不能总是接受假设“所有非ASCII字符都是坏的”的文化偏见。 对于需要使用非ASCII字符但偶尔需要剥离的上下文,Unicode的正断言更加合适。

当一个字符串的“length”属性为正(非零),但看起来像(即打印为空字符串)一个空字符串时,好的指示是该字符串中嵌入了零宽度、非打印字符。例如,在Chrome调试器中,我发现一个名为“textContent”的变量显示了这个问题:

> textContent
""
> textContent.length
7

这促使我想要查看字符串中的内容。

> encodeURI(textContent)
"%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B"

这一系列字节似乎属于某些Unicode字符族,这些字符被文字处理器插入到文档中,然后找到它们的方式进入数据字段。最常见的是这些符号出现在文档末尾。零宽空格 "%E2%80%8B" 可能是由CK-Editor(CKEditor)插入的。

encodeURI()  UTF-8     Unicode  html     Meaning
-----------  --------  -------  -------  -------------------
"%E2%80%8B"  EC 80 8B  U 200B   ​  zero-width-space
"%E2%80%8E"  EC 80 8E  U 200E   ‎  left-to-right-mark
"%E2%80%8F"  EC 80 8F  U 200F   ‏  right-to-left-mark

以下是相关参考链接:

http://www.fileformat.info/info/unicode/char/200B/index.htm

https://en.wikipedia.org/wiki/Left-to-right_mark

请注意,虽然嵌入字符的编码为UTF-8,但正则表达式中的编码不是。尽管该字符在字符串中以三个UTF-8字节的形式(在我这里)嵌入,但正则表达式中的指令必须使用两个字节的Unicode。实际上,UTF-8可以长达四个字节;它比Unicode不够紧凑,因为它使用高位(或位)来转义标准ascii编码。这在这里有所解释:

https://en.wikipedia.org/wiki/UTF-8


3
textContent = textContent.replace(/[\u{0080}-\u{FFFF}]/gu,""); 在IE浏览器中(至少IE 11)无法正常运行。它会出现错误:SCRIPT5021:_字符集范围无效_。 - Andrey Sorich

24

你可以使用以下的正则表达式来替换非ASCII字符

str = str.replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, '')

然而,请注意空格,冒号和逗号都是有效的ASCII字符,因此结果将会如下:

> str
"INFO] :, , ,  (Higashikurume)"

1
我不太擅长正则表达式,但知道.replace()方法需要将要替换的内容作为第一个参数,将第二个参数替换为它,例如.replace('要替换的文本', '用这个文本替换')。那么如何做到相反的效果,保留ASCII字符并删除其他字符呢?谢谢。 - NicoM
3
在正则表达式中,方括号[]内的字符表示匹配任意一个该位置可能出现的字符,而方括号中的字符前加上^则表示匹配除了方括号内指定的字符以外的任意一个字符。 - Zaffy

19
没有一个答案能够正确处理制表符、换行符、回车符,有些还不能处理扩展ASCII和Unicode字符。以下代码可以保留制表符和换行符,但删除控制字符和ASCII字符集之外的任何内容。点击“运行此代码段”按钮进行测试。未来(2020+?)将会推出一些新的JavaScript,可能需要使用\u{FFFFF},但目前还不需要。

console.log("line 1\nline2 \n\ttabbed\nF̸̡̢͓̳̜̪̟̳̠̻̖͐̂̍̅̔̂͋͂͐l̸̢̹̣̤̙͚̱͓̖̹̻̣͇͗͂̃̈͝a̸̢̡̬͕͕̰̖͍̮̪̬̍̏̎̕͘ͅv̸̢̛̠̟̄̿i̵̮͌̑ǫ̶̖͓͎̝͈̰̹̫͚͓̠̜̓̈́̇̆̑͜ͅ".replace(/[\x00-\x08\x0E-\x1F\x7F-\uFFFF]/g, ''))


这是一个不错的正则表达式,但它也会移除重音符号和表情符号。我不确定如何改进这个正则表达式以涵盖这些情况。 - Julio Vedovatto
对于寻找可能的解决方案,以删除Angular window.atob 和 DOMSanitizer.bypassSecurity...在将其转换为base64时出现无效字符(无论是%80, \uFFFF 还是未解释的空格),这是一个有效的解决方案。 - B. León

17

使用带有重音符号的 ASCII:

var str = str.replace(/[^\x00-\xFF]/g, "");

1
太棒了!它处理其他答案丢弃的大于127的ASCII值。 - user3413723
关于带有重音符号的alt文本怎么样...比如https://altcodeunicode.com/alt-codes-letter-e-with-accents/? - Stackedup

2
str = str.replace(/[\u{0080}-\u{10FFFF}]/gu,"");

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