【问题标题】:C regex how to match any string ending with " or any empty string?C正则表达式如何匹配任何以“结尾的字符串或任何空字符串?
【发布时间】:2015-09-02 09:20:17
【问题描述】:

我正在尝试生成代码以逐行从逗号分隔的文本文件中读取输入。我只对其中的 3 个字段感兴趣,所以我跳过了其余的字段。问题是其中2个字段是包含在引号中的字符串,其中一个实际上是可选的。

例如,两个连续的行可能如下所示:

0,,10004,10004,"Albany Hwy After Galliers Av","",-32.13649428,116.0176090070,3
0,,10005,10005,"Albany Hwy Armadale Kelmscott Hospital","Armadale Kelmscott Hospital",-32.13481555555560,116.017707222222,3

由于我对字符串不感兴趣(我只对其中的几个数字感兴趣),所以我只是使用 scanf 中的 * 运算符跳过它们。对于第一个字符串,这很容易,因为这是一个必填字段,所以我可以跳过第一个双引号匹配到所有内容的正则表达式,直到第二个双引号,如下所示:

\"%*[^\"]

我遇到的问题是第二个字段,就在第一个字段之后。问题是这个字段是可选的;因此它可能有文本,也可能没有。只要它没有,我上面列出的正则表达式就不能正常工作,并且该行的整个 scanf 操作都会失败。尽管我尽了最大的努力,但我无法生成成功匹配直到第二个双引号的所有内容以及匹配空字符串的正则表达式。有谁知道我如何修改我的正则表达式来执行这样的功能?

附言这是我的 scanf 操作的示例:

    res = sscanf(buf, "%*d,,%ld,%*ld,\"%*[^\"]\",\"%*[]\",%lf,%lf,%*d", &cursid, &curslat, &curslong);

【问题讨论】:

  • scanf family of functions使用正则表达式。
  • 对不起,我的错,这不是正则表达式。它只是利用 scanf 的 %[chars] 函数,其中读取所有匹配 [chars] 的内容。问题仍然在于我如何才能实现我想要做的事情。
  • 至于如何读取您的 CSV 文件,这并不像人们想象的那么简单,因为 CSV 文件格式通常包含许多极端情况,这使得它们比人们想象的更难解析。尝试找到一个现有的库来读取和解析您的文件。
  • fscanf 完全不适合阅读 CSV。您应该使用fgets 逐行阅读,然后自己解析字符串。但正如另一条评论中指出的那样,请尝试在那里找到一些代码。
  • 好吧,我正在使用 fgets 读取该行,然后使用 sscanf 对其进行解析。我没有使用 fscanf

标签: c regex string scanf


【解决方案1】:

以下是基本的 CSV 解析器:

void readCSVline(char *line);
char *readCSVfield(char *line, char *buf);
void readCSVdemo(void)
{
    char line[]= "0,,10004,10004,\"Albany Hwy After Galliers Av\",\"\",-32.13649428,116.0176090070,3";
    readCSVline(line);

}
/* readCSVline is where you put your "intelligence* about fields to read
 * and what to do with them
 */
void readCSVline(char *line)
{
    char field1[80], *lineptr=line;
    int nfields=0;

    while (*lineptr) {
        lineptr= readCSVfield(lineptr, field1);
        printf("%s\n", field1);
        nfields++;
    }
    printf("%d fields read.\n", nfields);
}
/* readCSVfield reads a field from a CSV line until the next comma or end-of-line.
 * It returns where the reading stopped.
 */
char *readCSVfield(char *line, char *buf)
{
    int instr= FALSE;   // track whether we are in a string
    char *cptr= line;

    while (*cptr)
    {
        if (instr) {
            if (*cptr=='"') {
                char cc= *++cptr;
                if (cc=='"')        // escaped double quote
                    *buf++ = '"';
                else {
                    *buf='\0';
                    cptr--;
                    instr= FALSE;
                }
            }
            else *buf++ = *cptr;
        }
        else switch (*cptr) {
        case '"': instr= TRUE; break;
        case ',': cptr++; *buf= '\0'; return(cptr);
        case ' ': case '\t': case '\n': case '\r': break;
        default: *buf++ = *cptr;
        }
        cptr++;
    }
    *buf= '\0';
    return(cptr);
}

注意:处理带引号的字符串中的换行符

解析器经常被调用者读取的行调用。为了能够处理带引号的字符串中的回车/换行,解析器必须通过获取下一行来处理看到\nreadCSVfield 的签名应包括行缓冲区及其大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多