删除ruby中的奇怪无效字符

我有一些XML内容(UTF-8),其中包含无效字符(当我尝试用Nokogiri::XML(content)解析内容时Line 2190, SyntaxError: PCDATA invalid Char value 15 nokogiri告诉我Line 2190, SyntaxError: PCDATA invalid Char value 15 )。

该字符在Sublime Text编辑器中显示为“SI”:

无效字符

当我尝试复制角色时,没有任何东西被复制,所以我甚至无法查找它。 当我在Atom编辑器中打开它时,不显示“SI”。 但是,当我使用右键单步执行字符时,我必须键入两次以覆盖放置“SI”字符的位置。

首先,这是什么角色? 第二:在Ruby中有没有办法删除这些字符。 我试着用content.chars.select{|i| i.valid_encoding?}.join content.chars.select{|i| i.valid_encoding?}.join但它不会删除该字符。

更新

我通过用ruby读取原始文件找到了这个角色。 字符是\u000F"\u000F".ord返回字符代码15 。 关于http://www.fileformat.info/info/unicode/char/000f/index.htm,这是一个SHIFT IN字符。 还有其他类似的人物吗? 我可以使用str.split("\u000F").join来删除它们,但如果还有其他这样的字符,这似乎不是一个好方法。 有任何想法吗?

如果字节序列实际上对编码无效(UTF-8),那么在ruby 2.1+中,您可以使用String#scrub方法。 默认情况下,它将使用“unicode replacement character”替换无效字符(通常在框中作为问号复制),但您也可以使用它来完全删除它们。

但是,正如您所注意到的,您的“奇怪字节”实际上是有效的UTF-8,它重现了unicode代码点“\ u000F”,即SHIFT IN控制字符。 (很好找出所涉及的实际字节/字符,这是最难的部分!)

因此,如果我们想删除它们,我们必须清楚“像这样的字符”的含义。 人物喜欢什么?

Nokogiri抱怨它在XML“PCDATA”(Parsed Character Data)区域中无效。 为什么它是合法的unicode / UTF-8,但在XML PCDATA中无效? 什么是XML字符数据的合法性? 我试图解决这个问题,但它让人感到困惑,因为规范显然说某些角色“气馁”(什么?),并且在我眼中做出与其他事情相矛盾的陈述。

我不确定Nokogiri将从PCData中删除哪些字符,我们必须查看Nokogiri源(或更可能是libxml源),或尝试询问有关nokogiri / libxml源的更多信息的人的问题。

但是,“\ u000F”是一个“控制字符”,你不太可能想要XML字符数据中的控制字符(除非你知道你这样做),并且XML规范似乎不鼓励控制字符(显然Nokogiri / libxml实际上不允许它们) ?)。 因此,解释“像这样的字符”的一种方法是“控制字符”。

您可以使用此正则表达式从字符串中删除所有控制字符,例如:

 "Some string \u000F more".gsub(/[\u0001-\u001A]/ , '') # remove control chars, unicode codepoints from 0001 to 001A # => "Some string more" 

如果我们将“像这样的字符”解释为任何不打印的字符 – 比“控制字符”更广泛的类别,并且将包括一些nokogiri根本没有问题。 我们可以通过使用ruby对正则表达式中unicode字符类的支持来尝试删除一些不仅仅是控制字符:

 some_string.gsub(/[^[:print:]]/ , '') 

[:print]被记录为相当模糊,因为“排除了控制字符和类似字符”,因此这与我们想要做的模糊规范相匹配。 🙂

所以它真的取决于我们所说的“像这样的人物”。 真的,“你喜欢这样的字符”可能意味着“Nokogiri / libxml拒绝允许的任何字符”,我恐怕没有真正回答这个问题,因为我不确定,也不能很容易搞清楚。 但是对于很多情况,删除控制字符,甚至更好地删除与[:print]不匹配的字符可能会很好,除非你有理由想要控制字符和类似字符(如果你知道你需要它们)记录分隔符,例如)。

如果不是删除,你想用unicode替换字符替换它们,这通常用于表示“我们无法处理的字节序列”:

 "Shift in: \u000F".gsub(/[^[:print:]]/, "\uFFFD") # => "Shift in:  " 

如果不是删除它们而是想以某种方式转义它们,它们可以在XML解析后重建……再次询问它,我会弄明白,但我现在还没有。 🙂

欢迎处理字符编码问题,它确实有时会让人感到困惑。

一种删除UTF-8文本中的控制字符但不是空格的方法。 Iconv将首先将字符串转换为UTF-8编码。 编码行允许您指定如何处理无效字符,但不删除控制字符。 gsub负责删除控制字符,但留下空白区域。 如果由于正则表达式约束而使用“NOT(NOT Control OR is Whitespace)”代替替换if(Is Control和NOT whitespace),则替换。 这在ruby 1.9.x中起作用,在1.8.7 REE中不起作用。

 require 'iconv' def only_valid_chars(text) return "" unless text text = Iconv.conv('UTF-8//IGNORE', 'UTF-8', text) text.encode('UTF-8', 'UTF-8', {:invalid => :replace, :undef => :replace, :replace => ""}) #remove control characters, keep white space and line endings text = text.gsub(/[^ [^[:cntrl:]] | [\s] ]/,'') return text end #text = "08-10-06 √¢¬Ä¬ì" #text = "08-10-06 â\u0080\u0093 Appr \n \r \r\n ABC" #only_valid_chars(text) 

我在读取带有Roo gem的xlsx文件的电子邮件时发生了同样的事情。

我从来不知道我的字符串中确切地说出了哪些字节/字符,但是因为我知道我会接受哪些字符,所以我只删除那些不匹配的字符,如下所示:

 email_chars = 'a-z0-9\.\-_@' clean_email = email.gsub(/[^#{email_chars}]/, '')