在C语言中,最简单的解析字符串的方法是什么?

3

我需要在C语言中解析这个字符串:

XFR 3 NS 207.46.106.118:1863 0 207.46.104.20:1863\r\n

能够获取字符串中的207.46.106.118部分和1863部分(即第一个IP地址)。

我知道可以逐个字符地查找并最终找到这些信息,但是如果字符串中的IP地址格式发生变化(数字位数减少),有没有更简单的方法来获取这些信息呢?


在C语言中使用正则表达式是否可行? - Oskar Kjellin
我不想仅仅为了这个任务而使用正则表达式库。 - Luca Matteis
2
最简单和最准确可能不是同一回事... - Mitch Wheat
7个回答

14

你可以使用来自C标准库的sscanf()函数。这里是一个获取IP和端口字符串的示例,假设地址前面的部分是固定的:

#include <stdio.h>

int main(void)
{
    const char *input = "XFR 3 NS 207.46.106.118:1863 0 207.46.104.20:1863\r\n";

    const char *format = "XFR 3 NS %15[0-9.]:%5[0-9]";
    char ip[16] = { 0 };  // ip4 addresses have max len 15
    char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max

    if(sscanf(input, format, ip, port) != 2)
        puts("parsing failed");
    else printf("ip = %s\nport = %s\n", ip, port);

    return 0;
}

格式字符串的重要部分是扫描集模式%15[0-9.]%5[0-9],它们将匹配由数字或点组成的最多15个字符的字符串(即IP地址不会被检查其格式是否正确),以及最多5位数字的字符串(这意味着无效的端口号超过2^16-1将会通过)。


请只翻译程序相关的内容,不要涉及IP地址和端口号。IP地址可能会更改(数字增加/减少)... 端口也一样。 - Luca Matteis
@Luca:你想将IP地址/端口作为字符串还是整数获取?你是否关心其余的字符串是否格式良好,或者你只对第一个IP地址感兴趣? - Christoph
是的,我需要地址/端口作为字符串。不关心其余部分。 - Luca Matteis
@Christoph:+1。scanf的使用非常好。你能解释一下它是如何工作的吗? - kolistivra

2

取决于定义文档格式的内容。在这种情况下,可能只需要将字符串分词并查找所需内容。只需使用strtok并在空格上拆分以获取207.46.106.118:1863,然后您可以再次进行分词(或手动扫描:)以获得正确的组件。


2
你可以使用strtok函数以空格为分隔符进行标记化,或者可以使用scanf家族中的一个来提取数据。
但是所有这些函数都有一个重要的警告,它们因安全和处理错误输入而臭名昭著。须谨慎使用。

2
循环至找到第一个'.',然后往回循环直到找到' '。向前循环直到找到':',每次遇到'.'或':'时构建子字符串。您可以检查子字符串的数量和长度以进行简单的错误检查。然后循环直到找到一个空格并获得1863部分。
如果字符串开头不变化太大,这个方法会很健壮。而且非常容易。如果字符串总是以 "XFR 3 NS " 开头,那么它甚至可以更简单。

1
在这种情况下,strok() 的用途微不足道,我会选择它。为了安全起见,您可以计算字符串中的“:”并且只有一个时才继续进行。

0
如果要解析的字符串格式良好,那么我会采用Daniel和Ukko的建议使用strtok()。
但是需要注意的是:strtok()会修改它解析的字符串。这并不总是你想要的。

0

这可能过于复杂,因为您说您不想使用正则表达式库,但是re2c程序将为您提供无需库的正则表达式解析:它生成正则表达式的DFSM作为C代码。 正则表达式在嵌入在C代码中的注释中指定。

现在看来似乎过度了,但如果您必须解析剩余的字符串,那么稍后这可能会成为一种舒适方式;修改一些正则表达式以调整或添加新语法要比修改一堆临时代币化代码更容易。 并且它可以使您正在解析的内容的结构在您的代码中更加清晰。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接