1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! セルの値と、A1 の形の参照
/// セルに入っているもの
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
/// 何も入っていない
Empty,
/// 数。日付も数で入っている。日付かどうかは書式で決まる
Number(f64),
/// 文字
Text(String),
/// 真偽
Boolean(bool),
/// #N/A や #DIV/0! のようなエラー
Error(String),
}
impl Value {
/// 数として読む。数でなければ None
pub fn number(&self) -> Option<f64> {
match self {
Value::Number(value) => Some(*value),
_ => None,
}
}
/// 文字として読む。文字でなければ None
pub fn text(&self) -> Option<&str> {
match self {
Value::Text(value) => Some(value),
_ => None,
}
}
/// 何も入っていないか
pub fn is_empty(&self) -> bool {
*self == Value::Empty
}
}
/// セル 1 つ
#[derive(Debug, Clone, PartialEq)]
pub struct Cell {
/// 列。1 から始まる
pub column: u32,
/// 書式の番号。styles.xml の cellXfs での位置
pub style: u32,
/// 入っているもの
pub value: Value,
/// 数式。ないときは空。`=` は含まない
pub formula: String,
}
/// 行 1 つ。値の入っているセルだけが、列の順に並ぶ
#[derive(Debug, Clone, Default)]
pub struct Row {
/// 行番号。1 から始まる
pub number: u32,
/// この行のセル
pub cell: Vec<Cell>,
}
impl Row {
/// 列で引く。そのセルがなければ None
pub fn at(&self, column: u32) -> Option<&Cell> {
// 列の順に並んでいるので、二分で引ける
match self.cell.binary_search_by(|one| one.column.cmp(&column)) {
Ok(index) => Some(&self.cell[index]),
Err(_) => None,
}
}
}
/// A1 の形の参照から列を読む。1 から始まる。読めなければ 0
pub fn column_of(reference: &str) -> u32 {
let mut result = 0;
for value in reference.bytes() {
if !value.is_ascii_alphabetic() {
break;
}
result = result * 26 + (value.to_ascii_uppercase() - b'A' + 1) as u32;
}
result
}
/// A1 の形の参照から行を読む。1 から始まる。読めなければ 0
pub fn row_of(reference: &str) -> u32 {
let mut result = 0;
let mut found = false;
for value in reference.bytes() {
if value.is_ascii_digit() {
result = result * 10 + (value - b'0') as u32;
found = true;
continue;
}
if found {
break;
}
}
result
}
/// 列の番号を A、B、… AA の形に直す
pub fn letter_of(column: u32) -> String {
if column == 0 {
return String::new();
}
let mut rest = column;
let mut result = Vec::new();
while rest > 0 {
let step = (rest - 1) % 26;
result.push(b'A' + step as u8);
rest = (rest - 1) / 26;
}
result.reverse();
String::from_utf8(result).unwrap_or_default()
}