删除 ruby 中奇怪的无效字符
Remove weird invalid character in ruby
我有一些 XML 内容 (UTF-8),其中包含无效字符(当我尝试使用 Nokogiri::XML(content)
解析内容时,nokogiri 告诉我 Line 2190, SyntaxError: PCDATA invalid Char value 15
)。
该字符在 Sublime Text 编辑器中显示为 "SI":
当我尝试复制角色时,没有任何内容被复制,所以我什至无法查找它。例如,当我在我的 Atom 编辑器中打开它时,"SI" 没有显示。但是,当我使用右键逐个字符时,我必须键入两次才能越过 "SI" 字符所在的位置。
首先,这是一个什么样的人物?第二:在 Ruby 中有没有办法删除这些字符。我用 content.chars.select{|i| i.valid_encoding?}.join
试过了,但它没有删除字符。
更新
我用ruby读取原文件找到了这个字符。字符是\u000F
和"\u000F".ord
returns字符代码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" 替换无效字符(通常表示为框中的问号),但您也可以使用它来完全删除它们。
但是,正如您所注意到的,您的 'weird byte' 实际上是有效的 UTF-8,表示 unicode 代码点“\u000F”,即 SHIFT IN
控制字符。 (很好地找出实际涉及的 bytes/character,这是困难的部分!)
所以如果我们想删除它们,我们必须清楚 "characters like that" 的意思。人物像什么?
Nokogiri 抱怨它在 XML "PCDATA"(已解析字符数据)区域无效。为什么它是合法的 unicode/UTF-8,但在 XML PCDATA 中无效? XML 字符数据中什么是合法的?我试图弄清楚,但它变得令人困惑,spec 显然是在说某些字符是 'discouraged'(什么?),并使我眼中的内容与其他事情相互矛盾。
我不确定 Nokogiri 究竟会禁止 PCData 中的哪些字符,我们必须查看 Nokogiri 源代码(或者更可能是 libxml 源代码),或者尝试向更了解 PCData 的人提问nokogiri/libxml的来源。
但是,“\u000F”是一个 "control character",您不太可能希望在 XML 字符数据中使用控制字符(除非您知道自己这样做),并且 XML 规范似乎不鼓励控制字符(显然 Nokogiri/libxml 实际上不允许它们?)。所以解释 "characters like this" 的一种方法是 "control characters"。
您可以使用此正则表达式从字符串中删除所有控制字符,例如:
"Some string \u000F more".gsub(/[\u0001-\u001A]/ , '') # remove control chars, unicode codepoints from 0001 to 001A
# => "Some string more"
如果我们将 "characters like this" 解释为任何不打印的字符 -- 比 "control characters" 更广泛的类别,并且将包括一些 nokogiri 完全没有问题的字符。我们可以尝试通过使用 ruby 对正则表达式中的 unicode 字符 类 的支持来删除更多的控制字符:
some_string.gsub(/[^[:print:]]/ , '')
[:print]
被相当模糊地记录为 "excludes control characters, and similar",所以这有点符合我们对我们想要做的事情的模糊规范。 :)
所以这真的取决于我们所说的 "characters like this" 是什么意思。真的,"characters like this" 对于你的情况可能意味着 "any char that Nokogiri/libxml will refuse to allow",恐怕我还没有真正回答 那个 问题,因为我不确定并且是无法轻易弄清楚。但在许多情况下,删除控制字符,或者甚至更好地删除不匹配的字符 [:print]
可能会很好,除非你有理由想要保留控制字符和类似字符(如果你知道你需要它们作为记录分隔符,例如)。
如果您不想删除,而是想用 unicode 替换字符替换它们,它通常用于代表 "byte sequence we couldn't handle":
"Shift in: \u000F".gsub(/[^[:print:]]/, "\uFFFD")
# => "Shift in: �"
如果你不想删除它们,而是想以某种方式转义它们,它们可以在 XML 解析后重建....再问一遍,我会弄清楚的,但我还没有但现在。 :)
欢迎处理字符编码问题,有时确实会让人感到困惑。
一种在 UTF-8 文本中删除控制字符的方法,但不是白色space。 Iconv 将首先将字符串转换为 UTF-8 编码。 encode 行允许您指定如何处理无效字符,但不会删除控制字符。 gsub 负责删除控制字符,但保留白色 space。 Substitute if "NOT ( NOT Control OR is Whitespace)" 用于代替 substitute if (Is Control and 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 文件读取电子邮件时。
我从来不知道我的字符串中出现了哪个 bytes/character,但是因为我知道我会接受哪些字符,所以我只是删除了那些不匹配的字符,如下所示:
email_chars = 'a-z0-9\.\-_@'
clean_email = email.gsub(/[^#{email_chars}]/, '')
我有一些 XML 内容 (UTF-8),其中包含无效字符(当我尝试使用 Nokogiri::XML(content)
解析内容时,nokogiri 告诉我 Line 2190, SyntaxError: PCDATA invalid Char value 15
)。
该字符在 Sublime Text 编辑器中显示为 "SI":
当我尝试复制角色时,没有任何内容被复制,所以我什至无法查找它。例如,当我在我的 Atom 编辑器中打开它时,"SI" 没有显示。但是,当我使用右键逐个字符时,我必须键入两次才能越过 "SI" 字符所在的位置。
首先,这是一个什么样的人物?第二:在 Ruby 中有没有办法删除这些字符。我用 content.chars.select{|i| i.valid_encoding?}.join
试过了,但它没有删除字符。
更新
我用ruby读取原文件找到了这个字符。字符是\u000F
和"\u000F".ord
returns字符代码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" 替换无效字符(通常表示为框中的问号),但您也可以使用它来完全删除它们。
但是,正如您所注意到的,您的 'weird byte' 实际上是有效的 UTF-8,表示 unicode 代码点“\u000F”,即 SHIFT IN
控制字符。 (很好地找出实际涉及的 bytes/character,这是困难的部分!)
所以如果我们想删除它们,我们必须清楚 "characters like that" 的意思。人物像什么?
Nokogiri 抱怨它在 XML "PCDATA"(已解析字符数据)区域无效。为什么它是合法的 unicode/UTF-8,但在 XML PCDATA 中无效? XML 字符数据中什么是合法的?我试图弄清楚,但它变得令人困惑,spec 显然是在说某些字符是 'discouraged'(什么?),并使我眼中的内容与其他事情相互矛盾。
我不确定 Nokogiri 究竟会禁止 PCData 中的哪些字符,我们必须查看 Nokogiri 源代码(或者更可能是 libxml 源代码),或者尝试向更了解 PCData 的人提问nokogiri/libxml的来源。
但是,“\u000F”是一个 "control character",您不太可能希望在 XML 字符数据中使用控制字符(除非您知道自己这样做),并且 XML 规范似乎不鼓励控制字符(显然 Nokogiri/libxml 实际上不允许它们?)。所以解释 "characters like this" 的一种方法是 "control characters"。
您可以使用此正则表达式从字符串中删除所有控制字符,例如:
"Some string \u000F more".gsub(/[\u0001-\u001A]/ , '') # remove control chars, unicode codepoints from 0001 to 001A
# => "Some string more"
如果我们将 "characters like this" 解释为任何不打印的字符 -- 比 "control characters" 更广泛的类别,并且将包括一些 nokogiri 完全没有问题的字符。我们可以尝试通过使用 ruby 对正则表达式中的 unicode 字符 类 的支持来删除更多的控制字符:
some_string.gsub(/[^[:print:]]/ , '')
[:print]
被相当模糊地记录为 "excludes control characters, and similar",所以这有点符合我们对我们想要做的事情的模糊规范。 :)
所以这真的取决于我们所说的 "characters like this" 是什么意思。真的,"characters like this" 对于你的情况可能意味着 "any char that Nokogiri/libxml will refuse to allow",恐怕我还没有真正回答 那个 问题,因为我不确定并且是无法轻易弄清楚。但在许多情况下,删除控制字符,或者甚至更好地删除不匹配的字符 [:print]
可能会很好,除非你有理由想要保留控制字符和类似字符(如果你知道你需要它们作为记录分隔符,例如)。
如果您不想删除,而是想用 unicode 替换字符替换它们,它通常用于代表 "byte sequence we couldn't handle":
"Shift in: \u000F".gsub(/[^[:print:]]/, "\uFFFD")
# => "Shift in: �"
如果你不想删除它们,而是想以某种方式转义它们,它们可以在 XML 解析后重建....再问一遍,我会弄清楚的,但我还没有但现在。 :)
欢迎处理字符编码问题,有时确实会让人感到困惑。
一种在 UTF-8 文本中删除控制字符的方法,但不是白色space。 Iconv 将首先将字符串转换为 UTF-8 编码。 encode 行允许您指定如何处理无效字符,但不会删除控制字符。 gsub 负责删除控制字符,但保留白色 space。 Substitute if "NOT ( NOT Control OR is Whitespace)" 用于代替 substitute if (Is Control and 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 文件读取电子邮件时。
我从来不知道我的字符串中出现了哪个 bytes/character,但是因为我知道我会接受哪些字符,所以我只是删除了那些不匹配的字符,如下所示:
email_chars = 'a-z0-9\.\-_@'
clean_email = email.gsub(/[^#{email_chars}]/, '')