Rust Calamine 可选解析器在第一个空单元格处停止读取行
Rust Calamine Optional Parser Stops Reading Rows at First Empty Cell
我一直在按照炉甘石文档中的示例从电子表格中提取值。
它们工作正常,但是当尝试使用解析空单元格时,可选的解析器示例不起作用。我想知道你们中是否有人能发现我在这里遗漏了什么。
我们有一个包含 5 列的电子表格。
这是有效的代码:
fn example<P: AsRef<Path>>(xls_path: P) -> Result<(), Error> {
let mut workbook: Xlsx<_> = open_workbook(xls_path)?;
let range = workbook
.worksheet_range("Billing")
.ok_or(Error::Msg("Cannot find 'Billing' sheet"))??;
let mut iter = RangeDeserializerBuilder::new().from_range(&range)?.enumerate();
while let Some((i, result)) = iter.next() {
println!("{:?}", result);
let (
invoice_num,
billing_date,
client,
amount,
date_received,
quarter,
direct_expenses,
expenses,
net,
total_expenses,
gross_profit,
): (
Option<String>,
Option<String>,
Option<String>,
Option<f64>,
Option<String>,
Option<String>,
Option<f64>,
Option<String>,
Option<String>,
Option<f64>,
Option<f64>,
) = result?;
println!("Number {:?}", i);
println!("Invoice #: {:?}", invoice_num);
// print them all..
}
Ok(())
}
手动将它们分配给可选值会导致打印每一行,无论其中哪些单元格为空。
现在示例代码采用这种方法:
#[derive(Serialize, Deserialize, Debug, Clone)]
struct RawExcelRow {
#[serde(rename = "INVOICE #", deserialize_with = "de_opt_string")]
invoice_num: Option<String>,
#[serde(rename = "BILLING DATE", deserialize_with = "de_opt_string")]
billing_date: Option<String>,
#[serde(rename = "CLIENT/PROJECT", deserialize_with = "de_opt_string")]
client_project: Option<String>,
#[serde(rename = "AMOUNT", deserialize_with = "de_opt_f64")]
amount: Option<f64>,
#[serde(rename = "DATE REC'D", deserialize_with = "de_opt_string")]
date_received: Option<String>,
}
fn example2() -> Result<(), Box<dyn std::error::Error>> {
if env::args().count() > 2 {
println!("{}", env::args().count());
return Err(Box::new(Error::from("Enter the filename or leave blank for default")));
}
let path_string = format!("{}", env::current_dir().unwrap().display());
let file_name = &env::args().nth(1).ok_or(Error::Msg("Unkown filename"))?;
let xls_path = Path::new(&path_string).join(file_name);
let mut excel: Xlsx<_> = open_workbook(xls_path)?;
let range = excel
.worksheet_range("Billing")
.ok_or(calamine::Error::Msg("Cannot find Billing sheet"))??;
let mut iter = RangeDeserializerBuilder::new().from_range::<_, RawExcelRowDate>(&range)?.enumerate();
while let Some((i, Ok(row))) = iter.next() {
println!("Number {}", i);
println!("Invoice #: {:?}", row.invoice_num);
// print them all..
}
Ok(())
}
反序列化器:
fn de_opt_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
let data_type = calamine::DataType::deserialize(deserializer);
match data_type {
Ok(calamine::DataType::Error(e)) => Ok(None),
Ok(calamine::DataType::Float(f)) => Ok(Some(f.to_string())),
Ok(calamine::DataType::Int(i)) => Ok(Some(i.to_string())),
Ok(calamine::DataType::String(s)) => Ok(Some(s)),
Ok(calamine::DataType::DateTime(d)) => Ok(Some(d.to_string())),
_ => Ok(None),
}
}
fn de_opt_f64<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
where
D: serde::Deserializer<'de>,
{
let data_type = calamine::DataType::deserialize(deserializer);
match data_type {
Ok(calamine::DataType::Error(_)) => Ok(None),
Ok(calamine::DataType::Float(f)) => Ok(Some(f)),
Ok(calamine::DataType::Int(i)) => Ok(Some(i as f64)),
_ => Ok(None),
}
}
每当我向结构添加一列时,都会发生这种情况 RawExcelRow
它会停在第一行,其中与该结构对应的列之一有一个空单元格。我期望看到的值是 None
但我看到的是错误:Deserializer error: missing field 'DATE REC'D'
因为 DATE REC'D 是其中一行中第一个为空的单元格。例如,第 18 行的 DATE REC'D 列中有第一个空单元格。所以只有第 1-17 行会被解析。
我查看了源代码,但我似乎无法找到它调用此错误而不是仅填写 None
值。我也尝试过使用基于访问者的反序列化器无济于事。
P.S.
调用 RangeDeserializerBuilder::with_headers(&COLUMNS)
其中 &COLUMNS
是一个列名数组,就像他们在示例中所做的那样,而不是 ::new()
没有区别,因为 ::new()
只是使用RangeDeserializer
的默认值,它使用所有 headers.
这个问题的答案有点难以捉摸,因为关于炉甘石的日期没有很好的记录。
link 中的答案提到提供属性 #[serde(default)]
以在缺少输入时使用 Option::default
值。
即使单元格为空,这也会导致炉甘石继续运行。尽管以“可选”解析器为例,炉甘石文档还是忽略了这一点。
知道这一点,这个问题与那个问题和那里的答案中列出的其他问题有点重复。但是,我不会删除这个问题,因为问题到底是什么并不是很明显。
解决方案
将结构更改为如下所示(并添加日期反序列化器)解决了问题:
#[derive(Serialize, Deserialize, Debug, Clone)]
struct RawExcelRow {
#[serde(default, rename = "INVOICE #", deserialize_with = "de_opt_string")]
invoice_num: Option<String>,
#[serde(default, rename = "BILLING DATE", deserialize_with = "de_opt_date")]
billing_date: Option<NaiveDate>,
#[serde(default, rename = "CLIENT/PROJECT", deserialize_with = "de_opt_string")]
client_project: Option<String>,
#[serde(default, rename = "AMOUNT", deserialize_with = "de_opt_f64")]
amount: Option<f64>,
#[serde(default, rename = "DATE REC'D", deserialize_with = "de_opt_date")]
date_received: Option<NaiveDate>,
}
我一直在按照炉甘石文档中的示例从电子表格中提取值。
它们工作正常,但是当尝试使用解析空单元格时,可选的解析器示例不起作用。我想知道你们中是否有人能发现我在这里遗漏了什么。
我们有一个包含 5 列的电子表格。
这是有效的代码:
fn example<P: AsRef<Path>>(xls_path: P) -> Result<(), Error> {
let mut workbook: Xlsx<_> = open_workbook(xls_path)?;
let range = workbook
.worksheet_range("Billing")
.ok_or(Error::Msg("Cannot find 'Billing' sheet"))??;
let mut iter = RangeDeserializerBuilder::new().from_range(&range)?.enumerate();
while let Some((i, result)) = iter.next() {
println!("{:?}", result);
let (
invoice_num,
billing_date,
client,
amount,
date_received,
quarter,
direct_expenses,
expenses,
net,
total_expenses,
gross_profit,
): (
Option<String>,
Option<String>,
Option<String>,
Option<f64>,
Option<String>,
Option<String>,
Option<f64>,
Option<String>,
Option<String>,
Option<f64>,
Option<f64>,
) = result?;
println!("Number {:?}", i);
println!("Invoice #: {:?}", invoice_num);
// print them all..
}
Ok(())
}
手动将它们分配给可选值会导致打印每一行,无论其中哪些单元格为空。
现在示例代码采用这种方法:
#[derive(Serialize, Deserialize, Debug, Clone)]
struct RawExcelRow {
#[serde(rename = "INVOICE #", deserialize_with = "de_opt_string")]
invoice_num: Option<String>,
#[serde(rename = "BILLING DATE", deserialize_with = "de_opt_string")]
billing_date: Option<String>,
#[serde(rename = "CLIENT/PROJECT", deserialize_with = "de_opt_string")]
client_project: Option<String>,
#[serde(rename = "AMOUNT", deserialize_with = "de_opt_f64")]
amount: Option<f64>,
#[serde(rename = "DATE REC'D", deserialize_with = "de_opt_string")]
date_received: Option<String>,
}
fn example2() -> Result<(), Box<dyn std::error::Error>> {
if env::args().count() > 2 {
println!("{}", env::args().count());
return Err(Box::new(Error::from("Enter the filename or leave blank for default")));
}
let path_string = format!("{}", env::current_dir().unwrap().display());
let file_name = &env::args().nth(1).ok_or(Error::Msg("Unkown filename"))?;
let xls_path = Path::new(&path_string).join(file_name);
let mut excel: Xlsx<_> = open_workbook(xls_path)?;
let range = excel
.worksheet_range("Billing")
.ok_or(calamine::Error::Msg("Cannot find Billing sheet"))??;
let mut iter = RangeDeserializerBuilder::new().from_range::<_, RawExcelRowDate>(&range)?.enumerate();
while let Some((i, Ok(row))) = iter.next() {
println!("Number {}", i);
println!("Invoice #: {:?}", row.invoice_num);
// print them all..
}
Ok(())
}
反序列化器:
fn de_opt_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
let data_type = calamine::DataType::deserialize(deserializer);
match data_type {
Ok(calamine::DataType::Error(e)) => Ok(None),
Ok(calamine::DataType::Float(f)) => Ok(Some(f.to_string())),
Ok(calamine::DataType::Int(i)) => Ok(Some(i.to_string())),
Ok(calamine::DataType::String(s)) => Ok(Some(s)),
Ok(calamine::DataType::DateTime(d)) => Ok(Some(d.to_string())),
_ => Ok(None),
}
}
fn de_opt_f64<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
where
D: serde::Deserializer<'de>,
{
let data_type = calamine::DataType::deserialize(deserializer);
match data_type {
Ok(calamine::DataType::Error(_)) => Ok(None),
Ok(calamine::DataType::Float(f)) => Ok(Some(f)),
Ok(calamine::DataType::Int(i)) => Ok(Some(i as f64)),
_ => Ok(None),
}
}
每当我向结构添加一列时,都会发生这种情况 RawExcelRow
它会停在第一行,其中与该结构对应的列之一有一个空单元格。我期望看到的值是 None
但我看到的是错误:Deserializer error: missing field 'DATE REC'D'
因为 DATE REC'D 是其中一行中第一个为空的单元格。例如,第 18 行的 DATE REC'D 列中有第一个空单元格。所以只有第 1-17 行会被解析。
我查看了源代码,但我似乎无法找到它调用此错误而不是仅填写 None
值。我也尝试过使用基于访问者的反序列化器无济于事。
P.S.
调用 RangeDeserializerBuilder::with_headers(&COLUMNS)
其中 &COLUMNS
是一个列名数组,就像他们在示例中所做的那样,而不是 ::new()
没有区别,因为 ::new()
只是使用RangeDeserializer
的默认值,它使用所有 headers.
这个问题的答案有点难以捉摸,因为关于炉甘石的日期没有很好的记录。
link 中的答案提到提供属性 #[serde(default)]
以在缺少输入时使用 Option::default
值。
即使单元格为空,这也会导致炉甘石继续运行。尽管以“可选”解析器为例,炉甘石文档还是忽略了这一点。
知道这一点,这个问题与那个问题和那里的答案中列出的其他问题有点重复。但是,我不会删除这个问题,因为问题到底是什么并不是很明显。
解决方案
将结构更改为如下所示(并添加日期反序列化器)解决了问题:
#[derive(Serialize, Deserialize, Debug, Clone)]
struct RawExcelRow {
#[serde(default, rename = "INVOICE #", deserialize_with = "de_opt_string")]
invoice_num: Option<String>,
#[serde(default, rename = "BILLING DATE", deserialize_with = "de_opt_date")]
billing_date: Option<NaiveDate>,
#[serde(default, rename = "CLIENT/PROJECT", deserialize_with = "de_opt_string")]
client_project: Option<String>,
#[serde(default, rename = "AMOUNT", deserialize_with = "de_opt_f64")]
amount: Option<f64>,
#[serde(default, rename = "DATE REC'D", deserialize_with = "de_opt_date")]
date_received: Option<NaiveDate>,
}