Linux系统编程(四):字符串处理

参考引用

  • UNIX 环境高级编程 (第3版)
  • 嵌入式Linux C应用编程-正点原子

1. 字符串输入/输出

1.1 字符串输出

  • 常用的字符串输出函数有 printf()、putchar()、puts()、fputc()、fputs()
    • printf() 可以按照自己规定的格式输出字符串信息,一般称为格式化输出
    • 而 putchar()、puts()、fputc()、fputs() 这些函数只能输出字符串,不能进行格式转换
    • 实际编程中,printf() 用的更多,但 putchar()、puts()、fputc()、fputs() 这些库函数比 printf() 使用更方便简单
    • 与 printf() 一样,putchar()、puts()、fputc()、fputs() 这些函数也是标准 I/O 函数,属于标准 C 库函数,所以需要包含头文件 ,并且它们也使用 stdio 缓冲
1.1.1 puts 函数
  • puts() 函数用来向标准输出设备(屏幕、显示器)输出字符串并自动换行,把字符串输出到标准输出设备,将 ‘\0’ 转换为换行符 ‘\n’
    #include 
    
    // s:需要进行输出的字符串
    // 返回值:成功返回一个非负数;失败将返回 EOF,EOF 其实就是 -1
    int puts(const char *s);
    
  • 测试
    #include 
    #include 
    
    int main(void) {
        char str[50] = "Linux app puts test";
    
        puts("Hello World!");
        puts(str);
    
        exit(0);
    }
    
    $ gcc test.c -o test
    $ ./test
    Hello World!
    Linux app puts test  # 自动换行
    
1.1.2 putchar 函数
  • putchar() 函数可以把参数 c 指定的字符(一个无符号字符)输出到标准输出设备,其输出可以是一个字符,可以是介于 0~127 之间的一个十进制整型数(输出其对应的 ASCII 码字符),也可是用 char 定义好的一个字符型变量
    #include 
    
    // c:需要进行输出的字符
    // 返回值:出错将返回 EOF
    int putchar(int c);
    
  • 示例
    putchar('A');
    
1.1.3 fputc 函数
  • fputc() 与 putchar() 类似,也用于输出参数 c 指定的字符(一个无符号字符),但 putchar() 只能输出到标准输出设备,而 fputc() 可把字符输出到指定的文件中,既可以是标准输出、标准错误设备,也可以是一个普通文件
    #include 
    
    // c:需要进行输出的字符
    // stream:文件指针
    // 返回值:成功时返回输出的字符;出错将返回 EOF
    int fputc(int c, FILE *stream);
    
  • 示例
    // 1. 使用 fputc 函数将字符输出到标准输出设备
    fputc('A', stdout);
    
    // 2. 使用 fputc 函数将字符输出到一个普通文件
    /* 创建一个文件 */
    fp = fopen("./new_file", "a");
    
    /* 输入字符到文件 */
    fputc('A', fp);
    
    /* 关闭文件 */
    fclose(fp);
    
1.1.4 fputs 函数
  • fputs()与 puts()类似,也用于输出一条字符串,但 puts() 只能输出到标准输出设备,而 fputs() 可把字符串输出到指定的文件中,既可以是标准输出、标准错误设备,也可以是一个普通文件
    #include 
    
    // s:需要输出的字符串
    // stream:文件指针
    // 返回值:成功返回非负数;失败将返回 EOF
    int fputs(const char *s, FILE *stream);
    
  • 示例
    // 1. 使用 fputs 输出字符串到标注输出设备
    fputs("Hello World! 1\n", stdout);
    
    // 2. 使用 fputs 输出字符串到一个普通文件
    /* 创建一个文件 */
    fp = fopen("./new_file", "a");
    
    /* 输入字符到文件 */
    fputs("Hello World! 1\n", fp);
    
    /* 关闭文件 */
    fclose(fp);
    

1.2 字符串输入

  • 常用的字符串输入函数有 scanf()、gets()、getchar()、fgetc()、fgets()
    • scanf() 与 gets()、getchar()、fgetc()、fgets() 这些函数相比,在功能上确实有它的优势,但是在使用上不如它们方便、简单、更易于使用
    • 与 scanf() 一样,gets()、getchar()、fgetc()、fgets() 这些函数也是标准 I/O 函数,属于标准 C 库函数,所以需要包含头文件 ,并且它们也使用 stdio 缓冲
1.2.1 gets 函数
  • gets() 函数用于从标准输入设备(如:键盘)中获取用户输入的字符串
    • 用户从键盘输入的字符串数据首先会存放在一个输入缓冲区中,gets() 函数会从输入缓冲区中读取字符串存储到字符指针变量 s 所指向的内存空间,当从输入缓冲区中读走字符后,相应的字符便不存在于缓冲区了
    • 输入的字符串中就算有空格也可直接输入,字符串输入完成后按回车即可,gets() 函数不检查缓冲区溢出
    #include 
    
    // s:指向字符数组的指针,用于存储字符串。
    // 返回值:如果成功,该函数返回指向 s 的指针;如果发生错误或者到达末尾时还未读取任何字符,则返回 NULL
    char *gets(char *s);
    

程序中使用 gets() 函数是非常不安全的,可能会出现 bug、出现不可靠性,可以使用 fgets() 代替

1.2.2 fgets 函数
  • fgets() 与 gets() 一样用于获取输入的字符串,但比 gets() 安全

    #include 
    
    // s:指向字符数组的指针,用于存储字符串
    // size:这是要读取的最大字符数
    // stream:文件指针
    char *fgets(char *s, int size, FILE *stream);
    
  • fgets() 与 gets() 的区别

    • gets() 只能从标准输入设备中获取输入字符串,而 fgets() 既可从标准输入设备获取字符串、也可从一个普通文件中获取输入字符串
    • fgets() 可以设置获取字符串的最大字符数
    • gets() 会将缓冲区中的换行符 ‘\n’ 读取出来,将其丢弃并替换为字符串结束符 ‘\0’;fgets() 也会将缓冲区中的换行符读取出来,但并不丢弃,而是作为字符串组成字符,读取完之后自动在末尾添加字符串结束字符 ‘\0’
  • fgets 从标准输入设备获取字符串

    #include 
    #include 
    
    int main(void) {
        char str[100] = {0};
    
        printf("请输入字符串: ");
        fgets(str, sizeof(str), stdin);
        printf("%s", str);
    
        exit(0);
    }
    
  • fgets 从普通文件中输入字符串

    #include 
    #include 
    
    int main(void) {
        char str[100] = {0};
        FILE *fp = NULL;
    
        /* 打开文件 */
        fp = fopen("./test_file", "r");
        if (NULL == fp) {
            perror("fopen error");
            exit(-1);
        }
    
        /* 从文件中输入字符串 */
        fgets(str, sizeof(str), fp);
        printf("%s", str);
    
        /* 关闭文件 */
        fclose(fp);
        exit(0);
    }
    
1.2.3 getchar 函数
  • getchar() 函数用于从标准输入设备中读取一个字符(一个无符号字符)
    • getchar() 函数也是从输入缓冲区读取字符数据,但只读取一个字符,包括空格、TAB 制表符、换行回车符等
    #include 
    
    // 返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF
    int getchar(void);
    
  • 测试
    #include 
    #include 
    
    int main(void) {
        int ch;
    
        ch = getchar();
        printf("ch: %c\n", ch);
    
        exit(0);
    }
    
    $ gcc test.c -o test
    $ ./test
    123
    ch: 1  # 只从输入缓冲区中读取一个字符
    
1.2.4 fgetc 函数
  • fgetc() 与 getchar() 一样,用于读取一个输入字符
    • fgetc() 与 getchar() 的区别在于:fgetc 可以指定输入字符的文件,既可以从标准输入设备输入字符,也可以从一个普通文件中输入字符
    #include 
    
    // stream:文件指针
    // 返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF
    int fgetc(FILE *stream);
    
  • 示例
    // 1. fgetc 从标准输入设备中输入字符
    int ch;
    ch = fgetc(stdin);
    
    // 2. fgetc 从普通文件中输入字符
    /* 打开文件 */
    fp = fopen("./test_file", "r");
    
    /* 从文件中输入一个字符 */
    ch = fgetc(fp);
    
    /* 关闭文件 */
    fclose(fp);
    

2. 字符串长度

  • C 语言函数库中提供了一个用于计算字符串长度的函数 strlen()
    #include 
    
    // s:需要进行长度计算的字符串,字符串必须包含结束字符 '\0'
    // 返回值:返回字符串长度(以字节为单位),字符串结束字符 '\0' 不计算在内
    size_t strlen(const char *s);
    

sizeof 和 strlen 的区别

  • sizeof 是 C 语言内置的操作符关键字,而 strlen 是 C 语言库函数
  • sizeof 仅用于计算数据类型的大小或者变量的大小,而 strlen 只能以结尾为 ‘\0’ 的字符串作为参数
  • 编译器在编译时就计算出了 sizeof 的结果,而 strlen 必须在运行时才能计算出来
  • sizeof 计算数据类型或变量会占用内存的大小,strlen 计算字符串实际长度
  • strlen 和 sizeof 对比测试
    #include 
    #include 
    #include 
    
    int main(void) {
        char str[50] = "Linux app strlen test!";
        char *ptr = str;
    
        printf("sizeof: %ld\n", sizeof(str));
        printf("strlen: %ld\n", strlen(str));
    
        puts("~~~~~~~~~~");
    
        printf("sizeof: %ld\n", sizeof(ptr));
        printf("strlen: %ld\n", strlen(ptr));
    
        exit(0);
    }
    
    $ gcc test.c -o test
    $ ./test
    sizeof: 50        # 数组变量 str 的大小
    strlen: 22        # strlen 始终计算的都是字符串的长度
    ~~~~~~~~~~
    sizeof: 8         # 指针变量 ptr 的大小
    strlen: 22        # strlen 始终计算的都是字符串的长度
    

3. 字符串拼接

  • C 语言函数库中提供了 strcat() 函数或 strncat() 函数用于将两个字符串连接(拼接)起来

3.1 strcat 函数

  • strcat() 函数会把 src 所指向的字符串追加到 dest 所指向的字符串末尾,所以必须要保证 dest 有足够的存储空间来容纳两个字符串,否则会导致溢出错误
    • dest 末尾的 ‘\0’ 结束字符会被覆盖,src 末尾的结束字符 ‘\0’ 会一起被复制过去,最终的字符串只有一个 ‘\0’
    #include 
    
    // dest:目标字符串
    // src:源字符串
    // 返回值:返回指向目标字符串 dest 的指针
    char *strcat(char *dest, const char *src);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char str1[100] = "Linux app strcat test, ";
        char str2[] = "Hello World!";
    
        strcat(str1, str2);
        puts(str1);
    
        exit(0);
    }
    

3.2 strncat 函数

  • strncat() 与 strcat() 的区别:strncat 可以指定源字符串追加到目标字符串的字符数量
    • 如果源字符串 src 包含 n 个或更多个字符,则 strncat() 将 n+1 个字节追加到 dest 目标字符串(src 中的 n 个字符加上结束字符 ‘\0’)
    #include 
    
    // dest:目标字符串
    // src:源字符串
    // n:要追加的最大字符数
    // 返回值:返回指向目标字符串 dest 的指针
    char *strncat(char *dest, const char *src, size_t n);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char str1[100] = "Linux app strcat test, ";
        char str2[] = "Hello World!";
    
        strncat(str1, str2, 5);
        puts(str1);
    
        exit(0);
    }
    

4. 字符串拷贝

  • C 语言函数库中提供了 strcpy()函数和 strncpy()函数用于实现字符串拷贝

4.1 strcpy 函数

  • strcpy() 会把 src(必须包含结束字符 ‘\0’)指向的字符串复制(包括字符串结束字符 ‘\0’)到 dest,所以必须保证 dest 指向的内存空间足够大,能够容纳下 src 字符串,否则会导致溢出错误
    #include 
    
    // dest:目标字符串
    // src:源字符串
    // 返回值:返回指向目标字符串 dest 的指针
    char *strcpy(char *dest, const char *src);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char str1[100] = {0};
        char str2[] = "Hello World!";
    
        strcpy(str1, str2);
        puts(str1);
    
        exit(0);
    }
    

4.2 strncpy 函数

  • strncpy() 与 strcpy() 的区别:strncpy() 可以指定从源字符串 src 复制到目标字符串 dest 的字符数量
    #include 
    
    // dest:目标字符串
    // src:源字符串
    // n:从 src 中复制的最大字符数
    // 返回值:返回指向目标字符串 dest 的指针
    char *strncpy(char *dest, const char *src, size_t n);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char str1[100] = "AAAAAAAAAAAAAAAAAAAAAAAA";
        char str2[] = "Hello World!";
        
        strncpy(str1, str2, 5);
        puts(str1);
        puts("~~~~~~~~~~~~~~~");
        strncpy(str1, str2, 20);
        puts(str1);
        
        exit(0);
    }
    

除了 strcpy() 和 strncpy() 之外,还可以使用 memcpy()、memmove() 以及 bcopy() 这些库函数实现拷贝操作,字符串拷贝本质上也只是内存数据的拷贝,所以这些库函数同样也是适用的

5. 内存填充

  • 经常需要将某一块内存中的数据全部设置为指定的值,如:在定义数组、结构体这种类型变量时,通常需要对其进行初始化操作,而初始化操作一般都是将其占用的内存空间全部填充为 0

5.1 memset 函数

  • memset() 函数用于将某一块内存的数据全部设置为指定的值

    #include 
    
    // s:需要进行数据填充的内存空间起始地址
    // c:要被设置的值,该值以 int 类型传递
    // n:填充的字节数
    // 返回值:返回指向内存空间 s 的指针
    void *memset(void *s, int c, size_t n);
    

    参数 c 虽然是以 int 类型传递,但 memset() 函数在填充内存块时是使用该值的无符号字符形式,也就是函数内部会将该值转换为 unsigned char 类型的数据,以字节为单位进行数据填充

  • 示例

    #include 
    #include 
    #include 
    
    int main(void) {
        char str[100];
        memset(str, 0x0, sizeof(str));  // 对数组 str 进行初始化操作,将其存储的数据全部设置为 0
    
        exit(0);
    }
    

5.2 bzero 函数

  • bzero() 函数用于将一段内存空间中的数据全部设置为 0
    #include 
    
    // s:内存空间的起始地址
    // n:填充的字节数
    void bzero(void *s, size_t n);
    
  • 测试
    #include 
    #include 
    #include 
    
    int main(void) {
        char str[100];
        bzero(str, sizeof(str));
    
        exit(0);
    }
    

6. 字符串比较

  • C 语言函数库提供了用于字符串比较的函数 strcmp() 和 strncmp()

6.1 strcmp 函数

  • strcmp 进行字符串比较,主要是通过比较字符串中字符对应的 ASCII 码值,根据 ASCII 编码依次比较 str1 和 str2 的每一个字符,直到出现了不同的字符,或者某一字符串已经到达末尾(遇见了字符串结束字符 ‘\0’)

    #include 
    
    // s1:进行比较的字符串 1
    // s2:进行比较的字符串 2
    /* 返回值
        小于 0,则表示 str1 小于 str2
        大于 0,则表示 str1 大于 str2
        等于 0,则表示字符串 str1 等于字符串 str2
    */
    int strcmp(const char *s1, const char *s2);
    
  • 测试

    #include 
    #include 
    #include 
    
    int main(void) {
        printf("%d\n", strcmp("ABC", "ABC"));
        printf("%d\n", strcmp("ABC", "a"));
        printf("%d\n", strcmp("a", "ABC"));
    
        exit(0);
    }
    

6.2 strncmp 函数

  • strncmp() 与 strcmp()函数一样,也用于对字符串进行比较操作,但最多比较前 n 个字符
    #include 
    
    // s1:参与比较的第一个字符串
    // s2:参与比较的第二个字符串
    // n:最多比较前 n 个字符
    // 返回值:返回值含义与 strcmp() 函数相同
    int strncmp(const char *s1, const char *s2, size_t n);
    
  • 测试
    #include 
    #include 
    #include 
    
    int main(void) {
        printf("%d\n", strncmp("ABC", "ABC", 3));
        printf("%d\n", strncmp("ABC", "ABCD", 3));
        printf("%d\n", strncmp("ABC", "ABCD", 4));
    
        exit(0);
    }
    

7. 字符串查找

  • C 语言函数库中提供了一些用于字符串查找的函数,包括 strchr()、strrchr()、strstr()、strpbrk()、index() 以及 rindex() 等
    • 如:从一个给定的字符串当中查找某一个字符或者一个字符串,并获取它的位置

7.1 strchr 函数

  • 使用 strchr() 函数可以查找到给定字符串当中的某一个字符
    • 字符串结束字符 ‘\0’ 也作为字符串的一部分,若将 c 指定为 ‘\0’,则函数将返回指向结束字符的指针
    #include 
    
    // s:给定的目标字符串
    // c:需要查找的字符
    // 返回值:返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c,则返回 NULL
    char *strchr(const char *s, int c);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char *ptr = NULL;
        char str[] = "Hello World!";
        ptr = strchr(str, 'W');
    
        if (NULL != ptr) {
            printf("Character: %c\n", *ptr);
            printf("Offset: %ld\n", ptr - str);
        }
    
        exit(0);
    }
    

7.2 strrchr 函数

  • strrchr() 与 strchr() 函数两者唯一不同的是,strrchr() 函数在字符串中是从后到前(或者称为从右向左)查找字符,找到字符第一次出现的位置就返回,返回值指向这个位置
    #include 
    
    char *strrchr(const char *s, int c);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char *ptr = NULL;
        char str[] = "I love my home";
    
        ptr = strchr(str, 'o');
        if (NULL != ptr)
            printf("strchr: %ld\n", ptr - str);
    
        ptr = strrchr(str, 'o');
        if (NULL != ptr)
            printf("strrchr: %ld\n", ptr - str);
    
        exit(0);
    }
    

7.3 strstr 函数

  • strstr() 可在给定的字符串 haystack 中查找第一次出现子字符串 needle 的位置,不包含结束字符 ‘\0’
    #include 
    
    // haystack:目标字符串
    // needle:需要查找的子字符串
    // 返回值:如果 haystack 中包含 needle,则返回该字符串首次出现的位置;如果未能找到 needle,则返回 NULL
    char *strstr(const char *haystack, const char *needle);
    
  • 示例
    #include 
    #include 
    #include 
    
    int main(void) {
        char *ptr = NULL;
        char str[] = "I love my home";
    
        ptr = strstr(str, "home");
        if (NULL != ptr) {
            printf("String: %s\n", ptr);
            printf("Offset: %ld\n", ptr - str);
        }
    
        exit(0);
    }
    

8. 字符串与数字互转

8.1 字符串转整形数据

  • C 函数库中提供了一系列函数用于实现将一个字符串转为整形数据,主要包括 atoi()、atol()、atoll() 以及 strtol()、strtoll()、strtoul()、strtoull() 等,它们之间的区别主要包括以下两个方面
    • 数据类型(int、long int、unsigned long 等)
    • 不同进制方式表示的数字字符串(八进制、十六进制、十进制)
8.1.1 atoi、atol、atoll 函数
  • atoi()、atol()、atoll() 三个函数可用于将字符串分别转换为 int、long int 以及 long long 类型的数据
    • 使用 atoi()、atol()、atoll() 函数只能转换十进制表示的数字字符串,即 0~9
    • 转换时跳过前面的空格字符,直到遇上数字字符或正负符号才开始做转换,再遇到非数字或字符串结束时(‘/0’)才结束转换
    #include 
    
    // nptr:需要进行转换的字符串
    // 返回值:分别返回转换之后得到的 int 类型数据、long int 类型数据以及 long long 类型数据
    int atoi(const char *nptr);
    long atol(const char *nptr);
    long long atoll(const char *nptr);
    
8.1.2 strtol、strtoll 函数
  • strtol()、strtoll() 两个函数可分别将字符串转为 long int 类型数据和 long long ing 类型数据,strtol()、strtoll() 可以实现将多种不同进制数表示的字符串转换为整形数据
#include 

// nptr:需要进行转换的目标字符串。
/* endptr
    char **类型的指针,如果 endptr 不为 NULL,则会将字符串中第一个无效字符的地址存储在*endptr 中
    如果根本没有数字,strtol() 或 strtoll()会将 nptr 的原始值存储在 *endptr 中(并返回 0)
    也可将参数 endptr 设置为 NULL,表示不接收相应信息
*/
// base:数字基数,参数 base 必须介于 2 和 36(包含)之间,或者是特殊值 0
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
8.1.3 strtoul、strtoull 函数
  • strtoul、strtoull 函数这两个函数使用方法与 strtol()、strtoll()一样,区别在于返回值的类型不同,strtoul()返回值类型是 unsigned long int,strtoull() 返回值类型是 unsigned long long int
    #include 
    
    unsigned long int strtoul(const char *nptr, char **endptr, int base);
    unsigned long long int strtoull(const char *nptr, char **endptr, int base);
    

8.2 字符串转浮点型数据

  • C 函数库中用于字符串转浮点型数据的函数有 atof()、strtod()、strtof()、strtold()
8.2.1 atof 函数
  • atof() 用于将字符串转换为一个 double 类型的浮点数据
    #include 
    
    double atof(const char *nptr);
    
  • 测试
    #include 
    #include 
    #include 
    
    int main(void) {
        printf("atof: %lf\n", atof("0.123"));
        printf("atof: %lf\n", atof("-1.1185"));
        printf("atof: %lf\n", atof("100.0123"));
    
        exit(0);
    }
    
8.2.2 strtod、strtof、strtold 函数
  • strtof()、strtod() 以及 strtold() 可分别将字符串转换为 float 类型数据、double 类型数据、long double 类型数据
    #include 
    
    double strtod(const char *nptr, char **endptr);
    float strtof(const char *nptr, char **endptr);
    long double strtold(const char *nptr, char **endptr);
    
  • 测试
    #include 
    #include 
    #include 
    
    int main(void) {
        printf("strtof: %f\n", strtof("0.123", NULL));
        printf("strtod: %lf\n", strtod("-1.1185", NULL));
        printf("strtold: %Lf\n", strtold("100.0123", NULL));
    
        exit(0);
    }
    

8.3 数字转字符串

#include 
#include 
#include 

int main(void) {
    char str[20] = {0};

    sprintf(str, "%d", 500);
    puts(str);

    memset(str, 0x0, sizeof(str));
    sprintf(str, "%f", 500.111);
    puts(str);

    memset(str, 0x0, sizeof(str));
    sprintf(str, "%u", 500);
    puts(str);

    exit(0);
    }

9. 给应用程序传参

  • open 打开的文件路径是固定的,如果需要打开另一个文件则需要修改代码、修改文件路径,然后再重新编译、运行,非常麻烦、不够灵活。可将这些可变信息通过参数形式传递给应用程序,如:当执行应用程序的时候,把需要打开的文件路径作为参数传递给应用程序,就可在不重新编译源码的情况下,通过传递不同的参数打开不同的文件

    • 传递进来的参数以字符串的形式存在,字符串的起始地址存储在 argv 数组中,参数 argc 表示传递进来的参数个数,包括应用程序自身路径名,多个不同的参数之间使用空格分隔开来
    int main(int argc, char *argv[]) {
        /* 代码 */
    }
    
  • 测试

    #include 
    #include 
    
    int main(int argc, char *argv[]) {
        int i = 0;
    
        printf("Number of parameters: %d\n", argc);
        for (i = 0; i < argc; i++)
            printf(" %s\n", argv[i]);
    
        exit(0);
    }
    
    $ gcc test.c -o test
    $ ./test 0 1 2
    Number of parameters: 4
     ./test
     0
     1
     2
    $ ./test a b c
    Number of parameters: 4
     ./test
     a
     b
     c
    

10. 正则表达式

  • 在许多的应用程序当中,通常会有这样的需要:给定一个字符串,检查该字符串是否符合某种条件或规则、或者从给定的字符串中找出符合某种条件或规则的子字符串,将匹配到的字符串提取出来
    • 例 1:检验用户输入的账号或密码是否符合它们定义的规则,如果不符合规则通常会提示用户按照正确的规则输入用户名或密码
    • 例 2:如给定一个字符串,在程序当中判断该字符串是否是一个 IP 地址

    对于这些需求,只需要通过一个正则表达式就可以实现

10.1 什么是正则表达式

  • 正则表达式,又称为规则表达式(Regular Expression)
    • 正则表达式通常被用来检索、替换那些符合某个模式(规则)的字符串
    • 正则表达式描述了一种字符串的匹配模式(pattern),可以用来检查一个给定的字符串中是否含有某种子字符串、将匹配的字符串替换或者从某个字符串中取出符合某个条件的子字符串
  • 如 “data?.txt” 这样的匹配模式可以将下列文件查找出来
    data.dat
    data1.dat
    data2.dat
    datax.dat
    dataN.dat
    
  • 正则表达式也是一个字符串,该字符串由普通字符(如:数字 0~9、大小写字母及其它字符)和特殊字符(称为 “元字符”)组成,由这些字符组成一个“规则字符串”,这个 “规则字符串”,用来表达对给定字符串的一种查找、匹配逻辑

10.2 正则表达式示例

  • 正则表达式实现流程
    • 1、编译正则表达式
    • 2、匹配正则表达式
    • 3、释放正则表达式
  • 匹配 URL 的正则表达式
    ^((ht|f)tps?)://[-A-Za-z0-9_]+(\.[-A-Za-z0-9_]+)+([-A-Za-z0-9_.,@?^=%&:/~+#]*[-A-Za-z0-9_@?^=%&/~+#])?$
    
  • 具体代码实现
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char *argv[]) {
        regmatch_t pmatch = {0};
        regex_t reg;
        char errbuf[64];
        int ret;
        char *sptr;
        int length;
        int nmatch; //最多匹配出的结果
        if (4 != argc) {
            /**********************************
                * 执行程序时需要传入两个参数:
                * arg1: 正则表达式
                * arg2: 待测试的字符串
                * arg3: 最多匹配出多少个结果
                **********************************/
            fprintf(stderr, "usage: %s   \n", argv[0]);
            exit(0);
        }
    
        /* 1、编译正则表达式 */
        if(ret = regcomp(&reg, argv[1], REG_EXTENDED)) {
            regerror(ret, &reg, errbuf, sizeof(errbuf));
            fprintf(stderr, "regcomp error: %s\n", errbuf);
            exit(0);
        }
        
        /* 赋值操作 */
        sptr = argv[2]; //待测试的字符串
        length = strlen(argv[2]);//获取字符串长度
        nmatch = atoi(argv[3]); //获取最大匹配数
    	
        /* 2、匹配正则表达式 */
        for (int j = 0; j < nmatch; j++) {
            char temp_str[100];
            /* 调用 regexec 匹配正则表达式 */
            if(ret = regexec(&reg, sptr, 1, &pmatch, 0)) {
                regerror(ret, &reg, errbuf, sizeof(errbuf));
                fprintf(stderr, "regexec error: %s\n", errbuf);
                goto out;
            }
            if(-1 != pmatch.rm_so) {
                if (pmatch.rm_so == pmatch.rm_eo) {//空字符串
                    sptr += 1;
                    length -= 1;
                    printf("\n"); //打印出空字符串
                    if (0 >= length)//如果已经移动到字符串末尾、则退出
                        break;
                    continue; //从 for 循环开始执行
                }
                memset(temp_str, 0x00, sizeof(temp_str));//清零缓冲区
                memcpy(temp_str, sptr + pmatch.rm_so,
                        pmatch.rm_eo - pmatch.rm_so);//将匹配出来的子字符串拷贝到缓冲区
                printf("%s\n", temp_str); //打印字符串
                sptr += pmatch.rm_eo;
                length -= pmatch.rm_eo;
                if (0 >= length)
                    break;
            }
        }
    	
        /* 3、释放正则表达式 */
    out:
        regfree(&reg);
        exit(0);
    }
    

你可能感兴趣的:(Linux系统编程,linux,服务器,正则表达式,字符串处理)