考虑一下,这条消息:
N,8545,01/02/2011 09:15:01.815,"RASTA OPTSTK 24FEB2011 1,150.00 CE",S,8.80,250,0.00,0
这只是一个样本。这个想法是,这是csv文件中的一行。现在,如果我要把它分成逗号,那么1150数字就会出现问题。
双引号内的字符串是可变长度的,但可以确定为一个“元素”(如果我可以使用该术语) 其他元素是由
分隔的元素我该如何解析它? (除了Ragel解析引擎)
Soham
答案 0 :(得分:4)
将字符串分成以逗号提供分隔的字段,表示逗号未嵌入带引号的字符串中。
快速执行此操作的方法是使用状态机。
boolean inQuote = false;
StringBuffer buffer= new StringBuffer();
// readchar() is to be implemented however you read a char
while ((char = readchar()) != -1) {
switch (char) {
case ',':
if (inQuote == false) {
// store the field in our parsedLine object for later processing.
parsedLine.addField(buffer.toString());
buffer.setLength(0);
}
break;
case '"':
inQuote = !inQuote;
// fall through to next target is deliberate.
default:
buffer.append(char);
}
}
请注意,尽管这提供了一个示例,但还有一些需要考虑的CSV文件(如引号中的嵌入式引号,或者是否适合在示例中去除外部引号)。
答案 1 :(得分:1)
如果您不想添加外部库,快速而又脏的解决方案是将双引号转换为\ 0(字符串标记的结尾),然后使用sscanf分别解析三个字符串。丑陋但应该工作。
假设输入格式正确(否则您将不得不添加错误处理):
for (i=0; str[i]; i++)
if (str[i] == '"') str[i] = 0;
str += sscanf(str, "%c,%d,%d/%d/%d %d:%d:%d.%d,", &var1, &var2, ..., &var9);
var10 = str; // it may be str+1, I don't remember if sscanf consumes also the \0
sscanf(str+strlen(var10), ",%c,%f,%d,%f,%d", &var11, &var12, ..., &var15);
如果您想立即免费var10
,您显然必须复制str
。
答案 2 :(得分:0)
这是一个函数,用于从作为FILE *
提供的输入文件中获取下一个CSV字段。它希望文件以文本模式打开,并支持带有嵌入式引号和换行符的带引号的字段。超过提供的缓冲区大小的字段将被截断。
int get_csv_field(FILE *f, char *buf, size_t size)
{
char *p = buf;
int c;
enum { QS_UNQUOTED, QS_QUOTED, QS_GOTQUOTE } quotestate = QS_UNQUOTED;
if (size < 1)
return EOF;
while ((c = getc(f)) != EOF)
{
if ((c == '\n' || c == ',') && quotestate != QS_QUOTED)
break;
if (c == '"')
{
if (quotestate == QS_UNQUOTED)
{
quotestate = QS_QUOTED;
continue;
}
if (quotestate == QS_QUOTED)
{
quotestate = QS_GOTQUOTE;
continue;
}
if (quotestate == QS_GOTQUOTE)
{
quotestate = QS_QUOTED;
}
}
if (quotestate == QS_GOTQUOTE)
{
quotestate = QS_UNQUOTED;
}
if (size > 1)
{
*p++ = c;
size--;
}
}
*p = '\0';
return c;
}
答案 3 :(得分:0)
我们自己libcsv的Robert Gamble怎么样?