如何在Ruby中删除不可打印/不可见字符?

11
有时,我会在字符串的中间遇到一些不可打印的恶意字符。这些字符串是用户输入的,所以我必须让我的程序正确接收它,而不是试图改变问题的源头。
例如,它们可能在字符串中间包含零宽度不换行空格。例如,在解析一个.po文件时,一个有问题的部分是文件中间的字符串"he is a man of god"。虽然一切似乎都正确,但使用irb检查后显示:
 "he is a man of god".codepoints
 => [104, 101, 32, 105, 115, 32, 97, 32, 65279, 109, 97, 110, 32, 111, 102, 32, 103, 111, 100] 

我相信我知道什么是BOM,而且我甚至能很好地处理它。然而有时我会在文件中间出现这样的字符,因此它不是BOM

我目前的方法是以一种非常恶心的方式删除我发现的所有“邪恶”字符:

text = (text.codepoints - CODEPOINTS_BlACKLIST).pack("U*")

我找到的最接近的方法是参考这篇文章,其中提到了正则表达式选项:print:。然而,它对我没有用:

"m".scan(/[[:print:]]/).join.codepoints
 => [65279, 109] 

所以问题是:如何在ruby中删除字符串中的所有不可打印字符?


如果您展示更多包含您正在处理的字符的源代码和样例字符串,将会非常有帮助。当前的样例并不能提供太多信息来确定编码集或者其他遇到的值。 - the Tin Man
@theTinMan 謝謝,我增加了一些細節到問題中。字符集是UTF-8,我相信,但我並不總是有這個信息,我有很多沒有BOM的文件。通過觀察中文翻譯,我認為這個文件至少部分上是unicode。 - fotanus
Ruby中有一个String方法叫做dump,它可以生成一个新的字符串,去除非打印字符并对特殊字符进行转义。String#dump是Ruby 2.3.0的文档,但我可以确认早在1.8.7版本的文档中也有介绍。 - Aaron
3个回答

21

试试这个:

>>"aaa\f\d\x00abcd".gsub(/[^[:print:]]/,'.')
=>"aaa.d.abcd"

这不幸地也会删除换行符。 - LouieGeetoo
这仍然无法删除一些字符,比如"\u200B"。 - Jonas S.

2

代码点65279是一个零宽不换行空格。它通常用作字节顺序标记(BOM)

您可以使用以下方法从字符串中删除它:

my_new_string = my_old_string.gsub!("\xEF\xBB\xBF".force_encoding("UTF-8"), '')

快速检查是否存在任何不可见字符的方法是检查字符串的长度,如果它比在IRB中看到的要高,则会有。


1
Ruby可以帮助您将一个多字节字符集转换为另一个。请查看搜索结果,并了解Ruby String的encode方法。
此外,Ruby的Iconv是您的好朋友。
最后,James Grey撰写了一系列文章,详细介绍了这个问题。
使用这些工具之一的事情是告诉它们将字符转码为视觉上相似的字符,或完全忽略它们。
处理备用字符集是我曾经做过的最烦人的事情之一,因为文件可以包含任何内容,但被标记为文本。您可能不会预料到它,然后您的代码就会崩溃或开始抛出错误,因为人们在将备用字符插入内容时非常巧妙。

放弃了...我认为没有更好的处理畸形文件的方法了。但是我接受你的答案,因为它对于那些使用格式正确的文件的人来说是一个很好的指南。 - fotanus
这些链接现在都无法使用 :( - Surya
@Surya,谢谢,是的,有几个链接是坏的,但不是全部。SO的方式是通过帮助维护网站来提升自己的能力。您可以通过提交编辑来修复问题,例如损坏的链接。请参阅“建议编辑如何工作”了解更多信息。 - the Tin Man
感谢您让我注意到这个功能。 - Surya

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