如何从字符串中去除不可打印的隐形字符?

5

如何从字符串中删除不可打印的不可见字符?

Ruby版本: 2.4.1

2.4.1 :209 > product.name.gsub(/[^[:print:]]/,'.')
 => "Kanha‬" 
2.4.1 :210 > product.name.gsub(/[^[:print:]]/,'.').length
 => 6 

2.4.1 :212 > product.name.gsub(/[\u0080-\u00ff]/, '').length
 => 6 

2.4.1 :214 > product.name.chars.reject { |char| char.ascii_only? and (char.ord < 32 or char.ord == 127) }.join.length
 => 6 

2.4.1 :216 > product.name.gsub(/[^[:print:]]/i, '').length
 => 6 

"Kanha"这个词有5个字母。然而,还有第6个字符是不可打印的。我该如何删除它?

通过搜索和查看stackoverflow(SO),我已经尝试了几种方法,但正如您所看到的,它们都没有帮助。

当我尝试与其他系统集成时,它会导致问题。


没有,我已经尝试过那些方法,但都不起作用,答案中提供的链接现在也无法使用 :( - Surya
product.name.each_char.all?(/[[:print:]]/) 这段代码出现了错误,ArgumentError: wrong number of arguments (given 1, expected 0)。我不明白你想表达什么。 - Surya
@cremno 你是怎么发现这个不想要的字符是 U+202C 的?而且 product.name.each_char.all?(/[[:print:]]/) 这段代码为什么会报错 ArgumentError:参数数量错误(应给定1个,但期望为0个)?我不明白你的意思,请解释一下。 - Surya
抱歉,我忘记了这个功能是在2.5而不是2.4中引入的。此外,已经接受的答案已经提到了如何查找这样的“隐形”字符。 - cremno
显示剩余2条评论
1个回答

10

首先,让我们找出问题所在的字符:

str = "Kanha‬"
p str.codepoints
# => [75, 97, 110, 104, 97, 8236]

前五个代码点在0到127之间,意味着它们是ASCII字符。可以安全地假设它们是字母K-a-n-h-a,尽管如果您想要的话这很容易验证:

p [75, 97, 110, 104, 97].map(&:ord)
# => ["K", "a", "n", "h", "a"]

那么,冒犯的字符是最后一个,即代码点8236。虽然这是十进制数字,但Unicode字符通常按其十六进制(基数16)编号列出。8236的十六进制是202C(8236.to_s(16) # => "202c"),所以我们只需Google搜索U+202C

谷歌很快告诉我们,违规字符是U+202C POP DIRECTIONAL FORMATTING,它是Unicode字符的“其他格式”类别的成员。维基百科说这个类别包括软连字号、连接控制字符(ZWNJ和ZWJ)、支持双向文本的控制字符和语言标记字符。
它还告诉我们该类别的“值”或代码为“Cf”。如果这些听起来像你想从字符串中删除的字符以及U+202C,则可以在Ruby正则表达式中使用\p{Cf}属性。您还可以使用\P{Print}(注意大写P)作为等效于[^[:print]]
str = "Kanha‬"
p str.length # => 6

p str.gsub(/\P{Print}|\p{Cf}/, '') # => "Kahna"
p str.gsub(/\P{Print}|\p{Cf}/, '').length # => 5

在repl.it上查看:https://repl.it/@jrunning/DutifulRashTag


2
非常感谢您。 那个可以工作。你是如何发现这个问题的? - Surya
1
cremno 在上面的评论中指出,冒犯的字符是 U+202C,所以很容易通过谷歌搜索找到,但我已经编辑了我的答案,添加了一些关于如何自己找出这个问题的细节。我从阅读 Ruby Regexp 文档中知道 \p{...} 将匹配任何 Unicode 类别(\P{...} 是它的反义词),所以只需要弄清楚哪个类别即可。 - Jordan Running
@JordanRunning 这真的非常有帮助。这是如何回答问题的完美例子。 - SamuelLJohnson

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