Java 解析csv,不要在单引号或双引号内拆分
我试图用java解析csv,但有以下问题:第二列是一个字符串(可能也包含逗号),用双引号括起来,除非字符串本身包含双引号,否则整个字符串都用单引号括起来。e、 g 线路可能会像这样断断续续:Java 解析csv,不要在单引号或双引号内拆分,java,csv,opencsv,Java,Csv,Opencsv,我试图用java解析csv,但有以下问题:第二列是一个字符串(可能也包含逗号),用双引号括起来,除非字符串本身包含双引号,否则整个字符串都用单引号括起来。e、 g 线路可能会像这样断断续续: someStuff,"hello", someStuff someStuff,"hello, SO", someStuff someStuff,'say "hello, world"', someStuff someStuff,'say "hello, world', someStuff someStuf
someStuff,"hello", someStuff
someStuff,"hello, SO", someStuff
someStuff,'say "hello, world"', someStuff
someStuff,'say "hello, world', someStuff
someStuff是其他元素的占位符,也可以包含相同样式的引号
我正在寻找一种以逗号分隔行的通用方法,除非用单引号或双引号括起来,以便将第二列作为字符串。对于第二列,我指的是字段:
- 你好
- 你好,那么
- 说“你好,世界”
- 说“你好,世界
public class CSVDemo {
public static void main(String[] args) throws IOException {
CSVDemo demo = new CSVDemo();
demo.process("input.csv");
}
public void process(String fileName) throws IOException {
String file = this.getClass().getClassLoader().getResource(fileName)
.getFile();
CSVReader reader = new CSVReader(new FileReader(file));
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
System.out.println(nextLine[0] + " | " + nextLine[1] + " | "
+ nextLine[2]);
}
}
}
使用opencsv的解决方案在最后一行失败,其中只有一个双引号括在单引号中:
someStuff | hello | someStuff
someStuff | hello, SO | someStuff
someStuff | 'say "hello, world"' | someStuff
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
opencsv似乎不支持这种开箱即用的方法。您可以扩展
com.opencsv.CSVParser
,并实现自己的算法来处理两种类型的引号。这是您将要更改的方法的来源,下面是一个存根,让您开始
class MyCSVParser extends CSVParser{
@Override
private String[] parseLine(String nextLine, boolean multi) throws IOException{
//Your algorithm here
}
}
如果你真的不能使用真正的CSV解析器,你可以使用正则表达式。这通常不是一个好主意,因为总有一些边缘情况你不能处理,但是如果格式严格按照你描述的那样,那么这可能会起作用
public void test() {
String[] tests = {"numeStuff,\"hello\", someStuff, someStuff",
"numeStuff,\"hello, SO\", someStuff, someStuff",
"numeStuff,'say \"hello, world\"', someStuff, someStuff"
};
/* Matches a field and a potentially empty separator.
*
* ( - Field Group
* \" - Start with a quote
* [^\"]*? - Non-greedy match on anything that is not a quote
* \" - End with a quote
* | - Or
* ' - Start with a strop
* [^']*? - Non-greedy match on anything that is not a strop
* ' - End with a strop
* | - Or
* [^\"'] - Not starting with a quote or strop
* [^,$]*? - Non-greedy match on anything that is not a comma or end-of-line
* ) - End field group
* ( - Separator group
* [,$] - Comma separator or end of line
* ) - End separator group
*/
Pattern p = Pattern.compile("(\"[^\"]*?\"|'[^\']*?\'|[^\"'][^,\r\n]*?)([,\r\n]|$)");
for (String t : tests) {
System.out.println("Matching: " + t);
Matcher m = p.matcher(t);
while (m.find()) {
System.out.println(m.group(1));
}
}
}
opencv似乎不支持这一点。不过,看看前面的问题和我的答案以及其他答案,以防它们有所帮助 你: 下面的示例中,请不要
notInsideComma
实际上是指“内部引号”。下面的代码可以扩展以检查引号和双引号
public static ArrayList<String> customSplitSpecific(String s)
{
ArrayList<String> words = new ArrayList<String>();
boolean notInsideComma = true;
int start =0, end=0;
for(int i=0; i<s.length()-1; i++)
{
if(s.charAt(i)==',' && notInsideComma)
{
words.add(s.substring(start,i));
start = i+1;
}
else if(s.charAt(i)=='"')
notInsideComma=!notInsideComma;
}
words.add(s.substring(start));
return words;
}
publicstaticarraylistcustomsplitspecific(字符串s)
{
ArrayList words=新的ArrayList();
布尔值NotInsideCommand=true;
int start=0,end=0;
对于(int i=0;i基本上您只需要跟踪,“
和,”
(修剪中间的部分)
当您遇到其中一种情况时,请将相应的标志(例如singleQuoteOpen、doubleQuoteOpen)设置为true,以指示它们处于打开状态,并且您处于忽略逗号模式
当满足适当的结束引号时,重置标志并继续切片元素
要执行检查,请在每个逗号处停止(当不处于忽略逗号模式时),并查看下一个字符(如果有)和修剪
注意:regex解决方案很好,也很短,但对于边缘情况(至少没有大麻烦)可定制性较差。如果每行使用单引号和双引号是一致的,可以选择每行相应的引号类型:
public class CSVDemo {
public static void main(String[] args) throws IOException {
CSVDemo demo = new CSVDemo();
demo.process("input.csv");
}
public void process(String fileName) throws IOException {
String file = this.getClass().getClassLoader().getResource(fileName)
.getFile();
CSVParser doubleParser = new CSVParser(',', '"');
CSVParser singleParser = new CSVParser(',', '\'');
String[] nextLine;
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
if (line.contains(",'") && line.contains("',")) {
nextLine = singleParser.parseLine(line);
} else {
nextLine = doubleParser.parseLine(line);
}
System.out.println(nextLine[0] + " | " + nextLine[1] + " | "
+ nextLine[2]);
}
}
}
}
你能更改数据吗?“说\“你好,世界\”
应该在opencsv中工作。数据在一个文件中,所以我可以在解析之前更改它…即读取行、更改/转义引号,然后拆分它