C/C++文件字符串解析

目的

我们需要解析DNS配置文件,该文件有时第一行、第二行是DNS地址,有时第三、第四行是DNS地址,并且格式不是完全固定,我们如何从该文件中获取到正确的DNS地址呢?

//第一种
sjdfaljfl
namespace 192.168.1.2
namespace 192.168.1.3
//第二种
namespace 192.168.1.2
namespace 192.168.1.3
//第三种
sjdfaljfl
namespace 192.168.1.2 #eth0
namespace 192.168.1.3 #eth0

我们要通过字符串的处理,保证我们能够读到正确的DNS地址。

C++打开文件

打开文件肯定要调用打开文件的函数,这里我们采用C语言中的标准库stdio.h中的函数,stdio .h 头文件定义了三个变量类型、一些宏和各种函数来执行输入和输出。

本次用到的函数为fopen,参数为“文件名”,“打开模式”

模式如下表所示:

“r”read: 为输入操作打开文件,文件必须存在。
“w”write: 为输出操作创建一个空文件,如果文件已存在,则将已有文件内容舍弃,按照空文件对待。
“a”append: 为输出打开文件,输出操作总是再文件末尾追加数据,如果文件不存在,创建新文件。
“r+”read/update: 为更新打开文件(输入和输出),文件必须存在
“w+”write/update: 为输入和输出创建一个空文件,如果文件已存在,则将已有文件内容舍弃,按照空文件对待。
“a+”append/update: 为输出打开文件,输出操作总是再文件末尾追加数据,如果文件不存在,创建新文件。

代码如下:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
    if(fd!=NULL)
    {
        qDebug("open file success!!");
    }

    //ui->setupUi(this);
}

C++读取字符串

打开文件之后,要把字符串读到文件中,后续再对字符串进行解析,达到对文件进行处理的目的。

stdio.h中读取文件流的方法有两种。

1int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
2char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

这里我们使用fgets函数获取数据。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
    if(fd!=NULL)
    {
        qDebug("open file success!!");
    }
    char dns[255];
    fgets(dns,255,fd);
    qDebug("%s",dns);
    //ui->setupUi(this);
}

至此,已经完成了第一行字符串的读取。

字符串处理

string .h 头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。

8char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
9int strcmp(const char *str1, const char *str2)str1 所指向的字符串和 str2 所指向的字符串进行比较。
10int strncmp(const char *str1, const char *str2, size_t n)str1str2 进行比较,最多比较前 n 个字节。
11int strcoll(const char *str1, const char *str2)str1str2 进行比较,结果取决于 LC_COLLATE 的位置设置。
14size_t strcspn(const char *str1, const char *str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
17char *strpbrk(const char *str1, const char *str2) 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。
18char *strrchr(const char *str, int c) 在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
19size_t strspn(const char *str1, const char *str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。
20char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。

以上函数都可以进行字符串比较,以确定当前我们是否能够将该行字符串确定为是DNS地址的字符串。

我们选择strncmp函数进行处理,比较其前n个字节,看是否符合我们的要求。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
    if(fd!=NULL)
        qDebug("open file success!!");
    char dns[255];
    fgets(dns,255,fd);
    qDebug("%s",dns);
    if(strncmp(dns,"namespace",6)==0)
        qDebug("this is dns");
    else
        qDebug("this is not dns");
    //ui->setupUi(this);
}

通过比较可以确认出是否属于namespace,我们还要将整个文件读完,以获取到所有的dns数据。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
    if(fd!=NULL)
        qDebug("open file success!!");
    char dns[255];
    while(!feof(fd))//当未读到结束时
    {
        fgets(dns,255,fd);
        qDebug("%s",dns);
        if(strncmp(dns,"namespace",6)==0)
            qDebug("this is dns");
        else
            qDebug("this is not dns");
    }
    //ui->setupUi(this);
}

至此,我们已经解析出了整个文件中的dns那一行数据,我们如何再准确的解析出dns地址呢?

我们使用C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。该函数的用法十分巧妙,第一次获取到的数据如果不符合需求,可以继续进行执行函数,注意传参,可继续获取剩余部分的字符串。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    char dns1[16];
    bool dns1_flag;
    //boot dns2_flag;
    char dns2[16];
    FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
    if(fd!=NULL)
        qDebug("open file success!!");
    char dns[255];
    while(!feof(fd))//当未读到结束时
    {
        fgets(dns,255,fd);
        qDebug("%s",dns);
        if(strncmp(dns,"namespace",6)==0){
            strtok(dns," ");//第一次分割,获取第一部分字符串。
            qDebug("%s",dns);
            char *tmp=strtok(NULL," ");//获取第二部分字符串,第二部分字符串即我们需要的字符串。
            if(dns1_flag==0)
            {
                dns1_flag=1;
                strcpy(dns1,tmp);
            }
            else
            {
                strcpy(dns2,tmp);
            }
            qDebug("%s",dns1);
            qDebug("this is dns");
        }
        else
            qDebug("this is not dns");
    }
    qDebug("dns1=%sdns2=%s",dns1,dns2);
    //ui->setupUi(this);
}

参考文章:C 标准库 - 参考手册 https://www.runoob.com/cprogramming/c-standard-library.html

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔通天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值