前提:这里考虑的各个单元格数据都不为空。
一、背景
实际的csv
文件是用英文逗号分隔的,是一个简单的文本,但是如果单元格内的数据本身就包含英文逗号呢?
以上这种情况,保存的文本大概是这个样子:
张三,"3500,4500","唱歌,游泳,骑马,"
二、解析
下面使用java
进行手动解析:
public class App {
public static void main(String[] args) {
// 张三,"3500,4500","唱歌,游泳,骑马,"
final String str = "张三,\"3500,4500\",\"唱歌,游泳,骑马,\"";
System.out.println(str);
final char[] arr = str.toCharArray();
int start = 0;
// 表示一个单元格内的数据就包含,
boolean complex = false;
int len = arr.length;
for (int i = 0; i < len; i++) {
char c = arr[i];
if (c == '"') { // 表示一个复合体的开始或者结束
if (complex) {
// 已经设置过complex标志,说明当前是一个复合体的结束"
final String item = new String(arr, start, i - start);
System.out.println(item);
complex = false;
i++;
} else {
// 未设置过complex标志,说明当前是一个复合体的开始"
start = i + 1;
complex = true;
}
} else if (c == ',' && !complex) { // 一个普通单元格的结束
final String item = new String(arr, start, i - start);
System.out.println(item);
start = i + 1;
}
}
}
}
控制台打印的内容:
张三,"3500,4500","唱歌,游泳,骑马,"
张三
3500,4500
唱歌,游泳,骑马,
三、思路
名词解释:
复合体
:这里指的是数据中就包含英文逗号,
的单元格。
普通单元格
:这里指的是数据中不包含英文逗号,
的单元格。
解析张三,"3500,4500","唱歌,游泳,骑马,"
这行csv数据,基本原理还是将它转换为char[]
字符数组,从头到尾逐个字符查看,对特殊字符进行标记、记录,这里特殊标记包括:
- 英文逗号
,
,它可能表示一个普通单元格
的结束,也可能只是复合体
中的一个普通字符 - 英文分号
"
,它用来将一个复合体
包裹起来,表示一个复合体
的开始或者是结束
对于一个单元格的数据,我需要知道它从哪里开始,即这里的start
变量值,到哪里结束,这里就是检测到结束的i
的位置,然后从arr
字符数组中构建一个String
,就得到了一个单元格的数据。
对于普通字符,不需要标记,跳过即可,考虑上面提到的两个特殊标志:
- 对于
,
来说,如果当前的complex
为false
,说明之前并没有碰到复合体
,那么它就是一个单元格数据的结束了,可以构建一个String
,并且可以预见下一个字符就应该是另一个单元格数据的开始,那么就需要将它设置为start = i + 1
,其实它并不完全正确,因为下一个有可能是特殊标记"
,但是它会被下面的这种情况所修正 - 对于
"
来说,它有可能表示复合体
的开始或者结束,这里使用一个布尔值complex
来进行区分,如果complex
的值为true
,说明当前遇到一个"
标记,并且之前也碰到一个"
才会使得complex
的值为true
,即可以构建一个final String item = new String(arr, start, i - start)
。同时需要设置complex
的值为false
,让它失效,同时紧挨着的下一个,
没有意义,手动跳过它:i++
。如果complex
的值为false
,说明是第一个遇到"
,表示复合体的开始,只需要设置start = i + 1
,同时设置complex = true
使之生效。
that’s all
thanks for reading~
111