Lin*_*orm 1 csv character-encoding windows-1252 rust
使用csv crate和最新的Rust版本1.31.0,我想读取ANSI(Windows 1252)编码的CSV文件,就像在UTF-8中一样.
在我阅读完整个文件后,我尝试过的事情(没有运气)Vec<u8>:
实际上,在我的公司,我们有很多CSV文件,ANSI编码.
另外,如果可能的话,我希望不要将整个文件加载到Vec<u8>一行但是一行读取(CRLF结束),因为许多文件很大(50 Mb或更多......).
在文件Cargo.toml中,我有这种依赖:
[dependencies]
csv = "1"
Run Code Online (Sandbox Code Playgroud)
test.csv包含以下保存为Windows-1252编码的内容:
Café;au;lait
Café;au;lait
Run Code Online (Sandbox Code Playgroud)
main.rs文件中的代码:
extern crate csv;
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::process;
fn example() -> Result<(), Box<Error>> {
let file_name = r"test.csv";
let file_handle = File::open(Path::new(file_name))?;
let reader = BufReader::new(file_handle);
let mut rdr = csv::ReaderBuilder::new()
.delimiter(b';')
.from_reader(reader);
// println!("ANSI");
// for result in rdr.byte_records() {
// let record = result?;
// println!("{:?}", record);
// }
println!("UTF-8");
for result in rdr.records() {
let record = result?;
println!("{:?}", record);
}
Ok(())
}
fn main() {
if let Err(err) = example() {
println!("error running example: {}", err);
process::exit(1);
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
UTF-8
error running example: CSV parse error: record 0 (line 1, field: 0, byte: 0): invalid utf-8: invalid UTF-8 in field 0 near byte index 3
error: process didn't exit successfully: `target\debug\test-csv.exe` (exit code: 1)
Run Code Online (Sandbox Code Playgroud)
使用rdr.byte_records()(取消注释代码的相关部分)时,输出为:
ANSI
ByteRecord(["Caf\\xe9", "au", "lait"])
Run Code Online (Sandbox Code Playgroud)
我怀疑这个问题是在指定的.特别是,不清楚为什么您对ByteRecordAPI 的使用不足.在csv crate中,字节记录专门用于这样的情况,其中您的CSV数据不是严格的UTF-8,而是使用其他编码,例如与ASCII兼容的Windows-1252.(ASCII兼容编码是ASCII是子集的编码.Windows-1252和UTF-8都是ASCII兼容的.UTF-16不是.)上面的代码示例显示你正在使用字节记录,但没有解释为什么这是不够的.
话虽如此,如果您的目标是将数据转换为Rust的字符串数据类型(String/ &str),那么您唯一的选择就是将CSV数据的内容从Windows-1252转码为UTF-8.这是必要的,因为Rust的字符串数据类型使用UTF-8作为其内存中表示.你不能有锈String/ &str是Windows的1252编码,因为Windows 1252是不是UTF-8的一个子集.
其他评论建议使用encoding箱子.但是,encoding_rs如果您的用例与编码标准解决的相同用例一致,我建议使用,该编码标准专门针对Web.幸运的是,我相信这种对齐存在.
为了满足您以流式方式读取CSV数据的标准,而无需先将整个内容加载到内存中,您需要在encoding_rs包装箱周围使用包装器为您实现流式解码.该encoding_rs_io箱提供了这个要求.(它在ripgrep内部用于在搜索UTF-8之前进行快速流解码.)
这是一个使用Rust 2018将上述所有内容放在一起的示例程序:
use std::fs::File;
use std::process;
use encoding_rs::WINDOWS_1252;
use encoding_rs_io::DecodeReaderBytesBuilder;
fn main() {
if let Err(err) = try_main() {
eprintln!("{}", err);
process::exit(1);
}
}
fn try_main() -> csv::Result<()> {
let file = File::open("test.csv")?;
let transcoded = DecodeReaderBytesBuilder::new()
.encoding(Some(WINDOWS_1252))
.build(file);
let mut rdr = csv::ReaderBuilder::new()
.delimiter(b';')
.from_reader(transcoded);
for result in rdr.records() {
let r = result?;
println!("{:?}", r);
}
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
与Cargo.toml:
[package]
name = "so53826986"
version = "0.1.0"
edition = "2018"
[dependencies]
csv = "1"
encoding_rs = "0.8.13"
encoding_rs_io = "0.1.3"
Run Code Online (Sandbox Code Playgroud)
并输出:
$ cargo run --release
Compiling so53826986 v0.1.0 (/tmp/so53826986)
Finished release [optimized] target(s) in 0.63s
Running `target/release/so53826986`
StringRecord(["Café", "au", "lait"])
Run Code Online (Sandbox Code Playgroud)
特别是,如果你换出rdr.records()了rdr.byte_records(),那么我们就可以更清楚地看到发生了什么:
$ cargo run --release
Compiling so53826986 v0.1.0 (/tmp/so53826986)
Finished release [optimized] target(s) in 0.61s
Running `target/release/so53826986`
ByteRecord(["Caf\\xc3\\xa9", "au", "lait"])
Run Code Online (Sandbox Code Playgroud)
即,您的输入包含Caf\xE9,但字节记录现在包含Caf\xC3\xA9.这是将Windows-1252代码点值233(编码为其文字字节\xE9)转换U+00E9 LATIN SMALL LETTER E WITH ACUTE为UTF-8编码的结果\xC3\xA9.
| 归档时间: |
|
| 查看次数: |
677 次 |
| 最近记录: |