UTF-8 Invalid Byte Sequences
Chances are, some of you have run into the issue with the invalid byte sequence in UTF-8 error when dealing with user-submitted data. AGoogle search shows that my hunch isn’t off.
Among the search results are plenty of answers—some using the deprecated iconv library—that might lead you to a sufficient fix. However, among the slew of queries are few answers on how to reliably replicate and test the issue.
In developing the Griddler gem we ran into some cases where the data being posted back to our controller had invalid UTF-8 bytes. For Griddler, our failing case needs to simulate the body of an email having an invalid byte, and encoded as UTF-8.
What are valid and invalid bytes? This table on Wikipedia tells us bytes 192, 193, and 245-255 are off limits. In ruby’s string literal we can represent this by escaping one of those numbers:
> "hi \255"
=> "hi \xAD"
There’s our string with the invalid byte! How do we know for sure? In that IRB session we can simulate a comparable issue by sending a message to the string it won’t like - like split or gsub.
> "hi \255".split(' ')
ArgumentError: invalid byte sequence in UTF-8
from (irb):9:in `split'
from (irb):9
from /Users/joel/.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in `<main>'
Yup. It certainly does not like that.
Let’s create a very real-world, enterprise-level, business-critical test case:
invalid_byte_spec.rb
require 'rspec'
def replace_name(body, name)
body.gsub(/joel/, name)
end
describe 'replace_name' do
it 'removes my name' do
body = "hello joel"
replace_name(body, 'hank').should eq "hello hank"
end
it 'clears out invalid UTF-8 bytes' do
body = "hello joel\255"
replace_name(body, 'hank').should eq "hello hank"
end
end
The first test passes as expected, and the second will fail as expected but not with the error we want. By adding that extra byte we should see an exception raised similar to what we simulated in IRB. Instead it’s failing in the comparison with the expected value.
1) replace_name clears out invalid UTF-8 bytes
Failure/Error: replace_name(body, 'hank').should eq "hello hank"
expected: "hello hank"
got: "hello hank\xAD"
(compared using ==)
# ./invalid_byte_spec.rb:17:in `block (2 levels) in <top (required)>'
Why isn’t it failing properly? If we pry into our running test we find out that inside our file the strings being passed around are encoded as ASCII-8BIT instead of UTF-8.
[2] pry(#<RSpec::Core::ExampleGroup::Nested_1>)> body.encoding
=> #<Encoding:ASCII-8BIT>
As a result we’ll have to force that string’s encoding to UTF-8:
it 'clears out invalid UTF-8 bytes' do
body = "hello joel\255".force_encoding('UTF-8')
replace_name(body, 'hank').should_not raise_error(ArgumentError)
replace_name(body, 'hank').should eq "hello hank"
end
By running the test now we will see our desired exception
1) replace_name clears out invalid UTF-8 bytes
Failure/Error: body.gsub(/joel/, name)
ArgumentError:
invalid byte sequence in UTF-8
# ./invalid_byte_spec.rb:4:in `gsub'
# ./invalid_byte_spec.rb:4:in `replace_name'
# ./invalid_byte_spec.rb:17:in `block (2 levels) in <top (required)>'
Finished in 0.00426 seconds
2 examples, 1 failure
Now that we’re comfortably in the red part of red/green/refactor we can move on to getting this passing by updating our replace_name method.
def replace_name(body, name)
body
.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
.gsub(/joel/, name)
end
And the test?
Finished in 0.04252 seconds
2 examples, 0 failures
For such a small piece of code we admittedly had to jump through some hoops. Through that process, however, we learned a bit about character encoding and how to put ourselves in the right position—through the red/green/refactor cycle—to fix bugs we will undoubtedly run into while writing software.
#encoding: utf-8
require 'json'
f="dsp-cpi"
File.open(f).each do |line|
line = line.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8')
end
UTF-8 Invalid Byte Sequences的更多相关文章
- maven filter 乱码,MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactI ...
- MalformedByteSequenceException: Invalid byte 1 of 1-byte
修改了线上程序的xml配置文件,重启后报如下错误: MalformedByteSequenceException: Invalid byte 1 of 1-byte 百度了下大体的意思是说文件的编码错 ...
- [字符编码]Invalid byte 1 of 1-byte UTF-8 sequence终极解决方案
今天在eclipse中编写pom.xml文件时,注释中的中文被eclipse识别到错误:Invalid byte 1 of 1-byte UTF-8 sequence,曾多次遇到该问题,问题的根源是: ...
- 读取xml文件报错:Invalid byte 2 of 2-byte UTF-8 sequence。
程序读取xml文件后,系统报“Invalid byte 2 of 2-byte UTF-8 sequence”错误,如何解决呢? 1.程序解析xml的时候,出现Invalid byte 2 of 2- ...
- Invalid byte 3 of 3-byte UTF-8 sequence
用maven编译,tomcat启动时报错:IOException parsing XML document from class path resource [applicationContext.x ...
- com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte ...
- tomcat部署新的项目的时候出现报错信息: Invalid byte tag in constant pool: 15
上面一堆tomcat启动的提示信息省略掉,下面是报错的具体信息:org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid ...
- xml中1字节的UTF-8序列的字节1无效([字符编码]Invalid byte 1 of 1-byte UTF-8 sequence终极解决方案)
今天在eclipse中编写pom.xml文件时,注释中的中文被eclipse识别到错误:Invalid byte 1 of 1-byte UTF-8 sequence,曾多次遇到该问题,问题的根源是: ...
- Xml读取异常--Invalid byte 1 of 1-byte UTF-8 sequence
xml读取异常Invalid byte 1 of 1-byte UTF-8 sequence org.dom4j.DocumentException: Invalid byte 1 of 1-byte ...
随机推荐
- java③
1.变量是什么? 变量====>一个数据在内存中 存储空间的表示! 在程序运行期间可以发生变化! *变量名 可以 迅速的从内存中 查询出 指定的变量! 2.数据类型: 数据类型 一共分为两种: ...
- zookeeper:springboot+dubbo配置zk集群并测试
1.springboot配置zk集群 1.1:非主从配置方法 dubbo: registry: protocol: zookeeper address: ,, check: false 1.2:主从配 ...
- dapper 简单多表查询
public List<Book> GetBookList() { List<Book> bList = null; try { using (var t = new SqlC ...
- Java输入输出小结
无论使用哪一种编程语言,输入输出都是我们首当其冲的,因此简单整理了 一下关于Java输入输出知识点,还有些内容摘自其它博客,忘见谅. 第一部分,让我们看一下Java的输出 public class M ...
- jaxb 组装及解析xml
参考 http://blog.csdn.net/yanan_seachange/article/details/7325708 a.添加依赖 b.建立绑定关系 c.测试 a.添加依赖 <depe ...
- 实力封装:Unity打包AssetBundle(二)
→前情提要:Unity最基本的AssetBundle打包方式. 第二种打包方式 Unity提供的BuildAssetBundles API还有一个重载形式,看下面↓↓ public static As ...
- day 03 变量与基本数据类型
变量的命名规范 一:变量命名的大前提,应该能够反映出变量值所记录内容 1:变量名只能由数字,字母,下划线组成 2:变量名不能以数字开头 3:变量名不能使用系统的关键字,不然可能会报错 二:变量名的命名 ...
- 笔记:Oracle查询重复数据并删除,只保留一条记录
1.查找表中多余的重复记录,重复记录是根据单个字段(Id)来判断 select * from 表 where Id in (select Id from 表 group byId having cou ...
- React Natived打包报错java.io.IOException: Could not delete path '...\android\support\v7'解决
问题详情 React Native打包apk时在第二次编译时候报错: java.io.IOException: Could not delete path 'D:\mycode\reactnative ...
- java网络编程ServerSocket类 和Socket类的常用构造方法及其方法
Socket类Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号.Socket(String host, int po ...