当前位置: 首页 > news >正文

Linux-C/C++《七、字符串处理》(字符串输入/输出、C 库中提供的字符串处理函数、正则表达式等)

        字符串处理在几乎所有的编程语言中都是一个绕不开的话题,在一些高级语言当中,对字符串的处理支 持度更是完善,譬如 C++、 C# Python 等。若在 C 语言中想要对字符串进行相关的处理,譬如将两个字符串进行拼接、字符串查找、两个字符串进行比较等操作,几乎是需要程序员自己编写字符串处理相关逻辑代码来实现字符串处理功能。
        好在 C 语言库函数中已经给我们提供了丰富的字符串处理相关函数,基本常见的字符串处理需求都可以直接使用这些库函数来实现,而不需要自己编写代码,使用这些库函数可以大大减轻编程负担。这些库函数大致可以分为字符串的输入、输出、合并、修改、比较、转换、复制、搜索等几类,本章将向大家介绍这些库函数的使用方法。
本章将会讨论如下主题内容。
字符串输入 / 输出;
C 库中提供的字符串处理函数;
给应用程序传参;
正则表达式。

1、字符串输入/输出

        在程序当中,经常需要在程序运行过程中打印出一些信息,将其输出显示到标准输出设备 stdout (譬如屏幕)或标准错误设备 stderr (譬如屏幕),譬如调试信息、报错信息、中间产生的变量的值等等,以实现对程序运行状态的掌控和分析。除了向 stdout stderr 输出打印信息之外,有时程序在运行过程中还需要从标准输入设备 stdin (譬如键盘)中读取字符串,将读取到的字符串进行解析,以指导程序的下一步动作、控制程序执行流程。

1.1 字符串输出

        常用的字符串输出函数有 putchar() puts() fputc() fputs() ,前面我们经常使用 printf() 函数来输出字符串信息,而并没有使用到 putchar() puts() fputc() fputs() 这些函数,原因在于 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.h> ,并且它们也使用 stdio 缓冲。
        puts 函数
        puts()函数用来向标准输出设备(屏幕、显示器)输出字符串并自行换行。把字符串输出到标准输出设备,将' \0 ' 转换为换行符 ' \n ' puts 函数原型如下所示(可通过 "man 3 puts" 命令查看):
#include <stdio.h>
int puts(const char *s);
        函数参数和返回值含义如下:
        s: 需要进行输出的字符串。
        返回值:成功返回一个非负数;失败将返回 EOF EOF 其实就是 -1
使用 puts() 函数连换行符 ' \n ' 都省了,函数内部会自动在其后添加一个换行符。所以,如果只是单纯输出字符串到标准输出设备,而不包含数字格式化转换操作,那么使用 puts() 会更加方便、简洁; puts() 虽然方便、简单,但也仅限于输出字符串,功能还是没有 printf() 强大。
        putchar 函数
        putchar()函数可以把参数 c 指定的字符(一个无符号字符)输出到标准输出设备,其输出可以是一个字符,可以是介于 0~127 之间的一个十进制整型数(包含 0 127 ,输出其对应的 ASCII 码字符),也可以是用 char 类型定义好的一个字符型变量。 putchar 函数原型如下所示(可通过 "man 3 putchar" 命令查看):
#include <stdio.h>
int putchar(int c);
        函数参数和返回值含义如下:
        c: 需要进行输出的字符。
        返回值:出错将返回 EOF
        fputc 函数
        fputc()与 putchar() 类似,也用于输出参数 c 指定的字符(一个无符号字符),与 putchar() 区别在于,putchar()只能输出到标准输出设备,而 fputc() 可把字符输出到指定的文件中,既可以是标准输出、标准错误设备,也可以是一个普通文件。
        fputc 函数原型如下所示:
#include <stdio.h>
int fputc(int c, FILE *stream);
        使用该函数需要包含头文件<stdio.h>
        函数参数和返回值含义如下:
        c: 需要进行输出的字符。
        stream: 文件指针。
        返回值:成功时返回输出的字符;出错将返回 EOF
        fputs 函数
        同理,fputs() puts() 类似,也用于输出一条字符串,与 puts() 区别在于, puts() 只能输出到标准输出设备,而 fputs() 可把字符串输出到指定的文件中,既可以是标准输出、标准错误设备,也可以是一个普通文件。
        函数原型如下所示:
#include <stdio.h>
int fputs(const char *s, FILE *stream);
        函数参数和返回值含义如下:
        s: 需要输出的字符串。
        stream: 文件指针。
        返回值:成功返回非负数;失败将返回 EOF

1.2字符串输入

        常用的字符串输入函数有 gets() getchar() fgetc() fgets() 。与 printf() 对应,在 C 库函数中同样也提供了格式化输入函数 scanf() scanf() gets() getchar() fgetc() fgets() 这些函数相比,在功能上确实有它的优势,但是在使用上不如它们方便、简单、更易于使用。
        与 scanf() 一样, gets() getchar() fgetc() fgets() 这些函数也是标准 I/O 函数,属于标准 C 库函数,所以需要包含头文件<stdio.h> ,并且它们也使用 stdio 缓冲。
        gets 函数
        gets()函数用于从标准输入设备(譬如键盘)中获取用户输入的字符串, gets() 函数原型如下所示:
#include <stdio.h>
char *gets(char *s);
        函数参数和返回值含义如下:
        s: 指向字符数组的指针,用于存储字符串。
        返回值:如果成功,该函数返回指向 s 的指针;如果发生错误或者到达末尾时还未读取任何字符,则返回 NULL
        用户从键盘输入的字符串数据首先会存放在一个输入缓冲区中,gets() 函数会从输入缓冲区中读取字符串存储到字符指针变量 s 所指向的内存空间,当从输入缓冲区中读走字符后,相应的字符便不存在于缓冲区了。
        输入的字符串中就算是有空格也可以直接输入,字符串输入完成之后按回车即可,gets() 函数不检查缓冲区溢出。
        gets()与 scanf() 的区别
        gets()除了在功能上不及 scanf 之外,它们在一些细节上也存在着不同:
         gets() 函数不仅比 scanf 简洁,而且,就算输入的字符串中有空格也可以,因为 gets() 函数允许输入的字符串带有空格、制表符,输入的空格和制表符也是字符串的一部分,仅以回车换行符作为字符串的分割符;而对于 scanf %s 格式输入的时候,空格、换行符、 TAB 制表符等都是作为字符串分割符存在,即分隔符前后是两个字符串,读取字符串时并不会将分隔符读取出来作为字符串的组成部分,一个%s 只能读取一个字符串,若要多去多个字符串,则需要使用多个 %s 、并且需要使用多个字符数组存储。
         gets() 会将回车换行符从输入缓冲区中取出来,然后将其丢弃,所以使用 gets() 读走缓冲区中的字符串数据之后,缓冲区中将不会遗留下回车换行符;而对于 scanf() 来说,使用 scanf() 读走缓冲区中的字符串数据时,并不会将分隔符(空格、TAB 制表符、回车换行符等)读走将其丢弃,所以使用 scanf() 读走缓冲区中的字符串数据之后,缓冲区中依然还存在用户输入的分隔符。 
        getchar 函数
        getchar()函数用于从标准输入设备中读取一个字符(一个无符号字符),函数原型如下所示:
#include <stdio.h>
int getchar(void);
        函数参数和返回值含义如下:
        无需传参
        返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF
        同样 getchar() 函数也是从输入缓冲区读取字符数据,但只读取一个字符,包括空格、 TAB 制表符、换行回车符等。
        fgetc 函数
        fgetc()与 getchar() 一样,用于读取一个输入字符,函数原型如下所示:
#include <stdio.h>
int fgetc(FILE *stream);
        函数参数和返回值含义如下:
        stream: 文件指针。
        返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF
        fgetc()与 getchar() 的区别在于, fgetc 可以指定输入字符的文件,既可以从标准输入设备输入字符,也可以从一个普通文件中输入字符,其它方面与 getchar 函数相同。

2、字符串长度

        C 语言函数库中提供了一个用于计算字符串长度的函数 strlen() ,其函数原型如下所示:
#include <string.h>
size_t strlen(const char *s);
        函数参数和返回值含义如下:
        s: 需要进行长度计算的字符串,字符串必须包含结束字符 ' \0 '
        返回值:返回字符串长度(以字节为单位),字符串结束字符 ' \0 ' 不计算在内。
        sizeof 和 strlen 的区别
        在程序当中,我们通常也会使用 sizeof 来计算长度,那 strlen sizeof 有什么区别呢?
         sizeof C 语言内置的操作符关键字,而 strlen C 语言库函数;
         sizeof 仅用于计算数据类型的大小或者变量的大小,而 strlen 只能以结尾为 ' \0 ' 的字符串作为参数;
         编译器在编译时就计算出了 sizeof 的结果,而 strlen 必须在运行时才能计算出来;
         sizeof 计算数据类型或变量会占用内存的大小, strlen 计算字符串实际长度。

3 、字符串拼接

        C 语言函数库中提供了 strcat() 函数或 strncat() 函数用于将两个字符串连接(拼接)起来, strcat 函数原 型如下所示:
        strcat 函数
#include <string.h>
char *strcat(char *dest, const char *src);
        函数参数和返回值含义如下:
        dest: 目标字符串。
        src: 源字符串。
        返回值:返回指向目标字符串 dest 的指针。
strcat() 函数会把 src 所指向的字符串追加到 dest 所指向的字符串末尾,所以必须要保证 dest 有足够的存储空间来容纳两个字符串,否则会导致溢出错误;dest 末尾的 ' \0 ' 结束字符会被覆盖, src 末尾的结束字符 '\0 '会一起被复制过去,最终的字符串只有一个 ' \0 '
        strncat 函数
        strncat()与 strcat() 的区别在于, strncat 可以指定源字符串追加到目标字符串的字符数量, strncat 函数原型如下所示:
#include <string.h>
char *strncat(char *dest, const char *src, size_t n);
        函数参数和返回值含义如下:
        dest: 目标字符串。
        src: 源字符串。
        n: 要追加的最大字符数。
        返回值:返回指向目标字符串 dest 的指针。
如果源字符串 src 包含 n 个或更多个字符,则 strncat() n+1 个字节追加到 dest 目标字符串( src 中的 n个字符加上结束字符' \0 ' )。

4、字符串拷贝

        C 语言函数库中提供了 strcpy() 函数和 strncpy() 函数用于实现字符串拷贝, strcpy 函数原型如下所示:
#include <string.h>
char *strcpy(char *dest, const char *src);
        函数参数和返回值含义如下:
        dest: 目标字符串。
        src: 源字符串。
        返回值:返回指向目标字符串 dest 的指针。
        strcpy()会把 src (必须包含结束字符 ' \0 ' )指向的字符串复制(包括字符串结束字符 ' \0 ' )到 dest ,所以必须保证 dest 指向的内存空间足够大,能够容纳下 src 字符串,否则会导致溢出错误。
        strncpy 函数
        strncpy()与 strcpy() 的区别在于, strncpy() 可以指定从源字符串 src 复制到目标字符串 dest 的字符数量,strncpy 函数原型如下所示:
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
        函数参数和返回值含义如下:
        dest: 目标字符串。
        src: 源字符串。
        n: src 中复制的最大字符数。
        返回值:返回指向目标字符串 dest 的指针。
src 所指向的字符串复制到 dest ,最多复制 n 个字符。当 n 小于或等于 src 字符串长度(不包括结束字符的长度)时,则复制过去的字符串中没有包含结束字符' \0 ' ;当 n 大于 src 字符串长度时,则会将 src 字符串的结束字符' \0 '也一并拷贝过去,必须保证 dest 指向的内存空间足够大,能够容纳下拷贝过来的字符串,否则会导致溢出错误。
        memcpy、 memmove bcopy
        除了 strcpy() strncpy() 之外,其实还可以使用 memcpy() memmove() 以及 bcopy() 这些库函数实现拷贝操作,字符串拷贝本质上也只是内存数据的拷贝,所以这些库函数同样也是适用的,在实际的编程当中,这些库函数也是很常用的,关于这三个库函数,这里不再给大家介绍,用法也非常简单,需要注意的就是目标内存空间与源内存空间是否有重叠的问题。
        关于三个库函数的使用方法,大家可以使用 man 手册进行查询。

5、内存填充

        在编程中,经常需要将某一块内存中的数据全部设置为指定的值,譬如在定义数组、结构体这种类型变量时,通常需要对其进行初始化操作,而初始化操作一般都是将其占用的内存空间全部填充为 0
        memset 函数
        memset()函数用于将某一块内存的数据全部设置为指定的值,其函数原型如下所示:
#include <string.h>
void *memset(void *s, int c, size_t n);
        函数参数和返回值含义如下:
        s: 需要进行数据填充的内存空间起始地址。
        c: 要被设置的值,该值以 int 类型传递。
        n: 填充的字节数。
        返回值:返回指向内存空间 s 的指针。
        参数 c 虽然是以 int 类型传递,但 memset() 函数在填充内存块时是使用该值的无符号字符形式,也就是函数内部会将该值转换为 unsigned char 类型的数据,以字节为单位进行数据填充。
        bzero 函数
        bzero()函数用于将一段内存空间中的数据全部设置为 0 ,函数原型如下所示:
#include <strings.h>
void bzero(void *s, size_t n);
函数参数和返回值含义如下:
s 内存空间的起始地址。
n 填充的字节数。
返回值: 无返回值。

6 、字符串比较

        C 语言函数库提供了用于字符串比较的函数 strcmp() strncmp() strcmp() 函数原型如下所示:
#include <string.h>
int strcmp(const char *s1, const char *s2);
        函数参数和返回值含义如下:
        s1: 进行比较的字符串 1
        s2: 进行比较的字符串 2
        返回值:
         如果返回值小于 0 ,则表示 str1 小于 str2
         如果返回值大于 0 ,则表示 str1 大于 str2
         如果返回值等于 0 ,则表示字符串 str1 等于字符串 str2
        strcmp 进行字符串比较,主要是通过比较字符串中的字符对应的 ASCII 码值, strcmp 会根据 ASCII 编码依次比较 str1 str2 的每一个字符,直到出现了不同的字符,或者某一字符串已经到达末尾(遇见了字符串结束字符' \0 ' )。
        strncmp 函数
        strncmp()与 strcmp() 函数一样,也用于对字符串进行比较操作,但最多比较前 n 个字符, strncmp() 函数原型如下所示:
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
        函数参数和返回值含义如下:
        s1: 参与比较的第一个字符串。
        s2: 参与比较的第二个字符串。
        n: 最多比较前 n 个字符。
        返回值:返回值含义与 strcmp() 函数相同。

7 、字符串查找

        字符串查找在平时的编程当中也是一种很常见的操作,譬如从一个给定的字符串当中查找某一个字符或者一个字符串,并获取它的位置。C 语言函数库中也提供了一些用于字符串查找的函数,包括 strchr() 、strrchr()、 strstr() strpbrk() index() 以及 rindex() 等。
        strchr 函数
        使用 strchr() 函数可以查找到给定字符串当中的某一个字符,函数原型如下所示:
#include <string.h>
char *strchr(const char *s, int c);
        函数参数和返回值含义如下:
        s: 给定的目标字符串。
        c: 需要查找的字符。
        返回值:返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c ,则返回 NULL
        字符串结束字符' \0 ' 也将作为字符串的一部分,因此,如果将参数 c 指定为 ' \0 ' ,则函数将返回指向结束字符的指针。strchr 函数在字符串 s 中从前到后(或者称为从左到右)查找字符 c ,找到字符 c 第一次出现的位置就返回,返回值指向这个位置,如果找不到字符 c 就返回 NULL
        strrchr 函数
        strrchr()与 strchr() 函数一样,它同样表示在字符串中查找某一个字符,返回字符第一次在字符串中出现的位置,如果没找到该字符,则返回值 NULL ,但两者唯一不同的是, strrchr() 函数在字符串中是从后到前(或者称为从右向左)查找字符,找到字符第一次出现的位置就返回,返回值指向这个位置,strrchr() 函数原型如下所示:
#include <string.h>
char *strrchr(const char *s, int c);
        函数参数和返回值含义与 strchr() 函数相同。
        strstr 函数
        与 strchr() 函数不同的是, strstr() 可在给定的字符串 haystack 中查找第一次出现子字符串 needle 的位置,不包含结束字符' \0 ' ,函数原型如下所示:
#include <string.h>
char *strstr(const char *haystack, const char *needle);
        函数参数和返回值含义如下:
        haystack: 目标字符串。
        needle: 需要查找的子字符串。
        返回值:如果目标字符串 haystack 中包含了子字符串 needle ,则返回该字符串首次出现的位置;如果未能找到子字符串 needle ,则返回 NULL
        其它函数
        除了上面介绍的三个函数之外,C 函数库中还提供其它的字符串(或字符)查找函数,譬如 strpbrk() 、index()以及 rindex() 等,这里便不再给大家一一介绍了,这些函数的用法都比较简单,大家通过 man 手册便可以快速了解到它们的使用方法。

8、 字符串与数字互转

        在编程中,经常会需要将数字组成的字符串转换为相应的数字、或者将数字转换为字符串,在 C 函数库中同样也提供了相应的函数,本小节就向大家介绍这些函数的用法。

8.1 字符串转整形数据

        C 函数库中提供了一系列函数用于实现将一个字符串转为整形数据,主要包括 atoi() atol() atoll() 以及strtol()、 strtoll() strtoul() strtoull() 等,它们之间的区别主要包括以下两个方面:
         数据类型( int long int unsigned long 等)。
         不同进制方式表示的数字字符串(八进制、十六进制、十进制)。
        atoi、 atol atoll 函数
        atoi()、 atol() atoll() 三个函数可用于将字符串分别转换为 int long int 以及 long long 类型的数据,它们的函数原型如下:
#include <stdlib.h>
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
        函数参数和返回值含义如下:
        nptr: 需要进行转换的字符串。
        返回值:分别返回转换之后得到的 int 类型数据、 long int 类型数据以及 long long 类型数据。
目标字符串 nptr 中可以包含非数字字符,转换时跳过前面的空格字符(如果目标字符串开头存在空格字符),直到遇上数字字符或正负符号才开始做转换,而再遇到非数字或字符串结束时(' /0 ') 才结束转换,并将结果返回。
        使用 atoi() atol() atoll() 函数只能转换十进制表示的数字字符串,即 0~9
        strtol、 strtoll 函数
        strtol()、 strtoll() 两个函数可分别将字符串转为 long int 类型数据和 long long ing 类型数据,与 atol() 、atoll()之间的区别在于, strtol() strtoll() 可以实现将多种不同进制数(譬如二进制表示的数字字符串、八进制表示的数字字符串、十六进制表示的数数字符串)表示的字符串转换为整形数据,其函数原型如下所示:
#include <stdlib.h>
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
        函数参数和返回值含义如下:
        nptr: 需要进行转换的目标字符串。
        endptr: char ** 类型的指针,如果 endptr 不为 NULL ,则 strtol() strtoll() 会将字符串中第一个无效字符的地址存储在*endptr 中。如果根本没有数字, strtol() strtoll() 会将 nptr 的原始值存储在 *endptr 中(并返回 0 )。也可将参数 endptr 设置为 NULL ,表示不接收相应信息。
        base: 数字基数,参数 base 必须介于 2 36 (包含)之间,或者是特殊值 0 。参数 base 决定了字符串转换为整数时合法字符的取值范围,譬如,当 base=2 时,合法字符为 ' 0 ' ' 1 ' (表示是一个二进制表示的数字字符串);当 base=8 时,合法字符为 ' 0 ' ' 1 ' ' 2 ' ' 3 '……' 7 ' (表示是一个八进制表示的数字字符串);当 base=16 时,合法字符为 ' 0 ' ' 1 ' ' 2 ' ' 3 '……' 9 ' ' a '……' f ' (表示是一个十六进制表示的数字字符串);当 base 大于 10 的时候, ' a ' 代表 10 ' b ' 代表 11 ' c ' 代表 12 ,依次类推, ' z ' 代表 35 (不区分大小写)。
        返回值:分别返回转换之后得到的 long int 类型数据以及 long long int 类型数据。
        需要进行转换的目标字符串可以以任意数量的空格或者 0 开头,转换时跳过前面的空格字符,直到遇上数字字符或正负符号(' + ' ' - ' )才开始做转换,而再遇到非数字或字符串结束时 (' /0 ') 才结束转换,并将结果返回。
        在 base=0 的情况下,如果字符串包含一个了“ 0x ”前缀,表示该数字将以 16 为基数;如果包含的是“0 ”前缀,表示该数字将以 8 为基数。
        当 base=16 时,字符串可以使用“ 0x ”前缀。
        strtoul、 strtoull 函数
        这两个函数使用方法与 strtol() strtoll() 一样,区别在于返回值的类型不同, strtoul() 返回值类型是 unsigned long int, strtoull() 返回值类型是 unsigned long long int ,函数原型如下所示:
#include <stdlib.h>
unsigned long int strtoul(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr, int base);
        函数参数与 strtol() strtoll() 一样,这里不再重述!

8.2 字符串转浮点型数据

        C 函数库中用于字符串转浮点型数据的函数有 atof() strtod() strtof() strtold()
        atof 函数
        atof()用于将字符串转换为一个 double 类型的浮点数据,函数原型如下所示:
#include <stdlib.h>
double atof(const char *nptr);
        函数参数和返回值含义如下:
        nptr: 需要进行转换的字符串。
        返回值:返回转换得到的 double 类型数据。
        strtod、 strtof strtold 函数
        strtof()、 strtod() 以及 strtold() 三个库函数可分别将字符串转换为 float 类型数据、 double 类型数据、 long double 类型数据,函数原型如下所示:
#include <stdlib.h>
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
long double strtold(const char *nptr, char **endptr);
        函数参数与 strtol() 含义相同,但是少了 base 参数。

8.3 数字转字符串

        数字转换为字符串推荐大家使用前面介绍的格式化 IO 相关库函数,譬如使用 printf() 将数字转字符串、并将其输出到标准输出设备或者使用 sprintf() snprintf() 将数字转换为字符串并存储在缓冲区中,具体的使用方法,3.11 内容中已经给大家进行了详细介绍,这里不再重述。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 打开的文件路径是固定的,意味着如果需要打开另一个文件则需要修改代码、修改文件路径,然后再重新编译、运行,非常麻烦、不够灵活。其实
可以将这些可变的信息通过参数形式传递给应用程序,譬如,当执行应用程序的时候,把需要打开的文件路径作为参数传递给应用程序,就可以在不重新编译源码的情况下,通过传递不同的参数打开不同的文件。当然这里只是举个例子,不同应用程序需根据其需要来设计。
         如果在执行应用程序时,需要向应用程序传递参数,则写法如下:
int main(int argc, char *argv[])
{/* 代码 */
}
        传递进来的参数以字符串的形式存在,字符串的起始地址存储在 argv 数组中,参数 argc 表示传递进来的参数个数,包括应用程序自身路径名,多个不同的参数之间使用空格分隔开来,如果参数本身带有空格、则可以使用双引号" " 或者单引号 ' ' 的形式来表示。

10、正则表达式

10.1 初识正则表达式

        正则表达式,又称为规则表达式(英语: Regular Expression ),正则表达式通常被用来检索、替换那些
符合某个模式(规则)的字符串,正则表达式描述了一种字符串的匹配模式( pattern ),可以用来检查一个给定的字符串中是否含有某种子字符串、将匹配的字符串替换或者从某个字符串中取出符合某个条件的子字符串。
        在 Linux 系统下运行命令的时候,相信大家都使用过 ? * 通配符来查找硬盘上的文件或者文本中的某个字符串,? 通配符匹配 0 个或 1 个字符,而 * 通配符匹配 0 个或多个字符,譬如 "data?.txt" 这样的匹配模式可以将下列文件查找出来:
data.dat
data1.dat
data2.dat
datax.dat
dataN.dat
        尽管使用通配符的方法很有用,但它还是很有限,正则表达式则更加强大、更加灵活。
        正则表达式其实也是一个字符串,该字符串由普通字符(譬如,数字 0~9 、大小写字母以及其它字符)和特殊字符(称为“元字符”)所组成,由这些字符组成一个“规则字符串”,这个“规则字符串”用来表达对给定字符串的一种查找、匹配逻辑。
        许多程序设计语言都支持正则表达式。譬如,在 Perl 中就内建了一个功能强大的正则表达式引擎、 Python提供了内置模块 re 用于处理正则表达式,正则表达式这个概念最初是由 Unix 中的工具软件(例如 sed 和grep)普及开的,使用过 sed 命令的朋友想必对正则表达式并不陌生。同样,在 C 语言函数库中也提供了用于处理正则表达式的接口供程序员使用。

11、C 语言中使用正则表达式

编译正则表达式
匹配正则表达式
释放正则表达式
匹配 URL 的正则表达式:
^((ht|f)tps?)://[-A-Za-z0-9_]+(\.[-A-Za-z0-9_]+)+([-A-Za-z0-9_.,@?^=%&:/~+#]*[-A-Za-z0-9_@?^=%&/~+#])?$
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
#include <string.h>
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 <regex> <string> <nmatch>\n", argv[0]);exit(0);}/* 编译正则表达式 */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]); //获取最大匹配数/* 匹配正则表达式 */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;}}/* 释放正则表达式 */
out:regfree(&reg);exit(0);
}

相关文章:

Linux-C/C++《七、字符串处理》(字符串输入/输出、C 库中提供的字符串处理函数、正则表达式等)

字符串处理在几乎所有的编程语言中都是一个绕不开的话题&#xff0c;在一些高级语言当中&#xff0c;对字符串的处理支 持度更是完善&#xff0c;譬如 C、 C# 、 Python 等。若在 C 语言中想要对字符串进行相关的处理&#xff0c;譬如将两个字符串进行拼接、字符串查找、两个…...

哈希动态规划dp_5

一.哈希 哈希&#xff08;Hashing&#xff09;是计算机科学中一种非常重要的技术&#xff0c;用于将输入的数据映射到固定大小的值&#xff08;哈希值&#xff09;上。哈希算法和哈希数据结构广泛应用于各种领域&#xff0c;包括数据查找、加密、缓存、数据库索引等。我们来详…...

电商分布式场景中如何保证数据库与缓存的一致性?实战方案与Java代码详解

文章目录 一、缓存一致性问题的本质写后读不一致&#xff1a;更新数据库后&#xff0c;缓存未及时失效并发读写竞争&#xff1a;多个线程同时修改同一数据缓存与数据库事务不同步&#xff1a;部分成功导致数据错乱 二、5大核心解决方案与代码实现方案1&#xff1a;延迟双删策略…...

DeepSeek-R1 大模型本地部署指南

文章目录 一、系统要求硬件要求软件环境 二、部署流程1. 环境准备2. 模型获取3. 推理代码配置4. 启动推理服务 三、优化方案1. 显存优化技术2. 性能加速方案 四、部署验证健康检查脚本预期输出特征 五、常见问题解决1. CUDA内存不足2. 分词器警告处理3. 多GPU部署 六、安全合规…...

【数据结构】 栈和队列

在计算机科学的世界里&#xff0c;数据结构是构建高效算法的基础。栈&#xff08;Stack&#xff09;和队列&#xff08;Queue&#xff09;作为两种基本且重要的数据结构&#xff0c;在软件开发、算法设计等众多领域都有着广泛的应用。今天&#xff0c;我们就来深入探讨一下栈和…...

用Python构建Mad Libs经典文字游戏

前言 Mad Libs 是一种经典的文字游戏,其中一名玩家向其他玩家询问各种词汇,如名词、动词、形容词等,而不提供任何上下文。然后将这些提示词插入到一个充满空白的故事模板中,从而创造出一个搞笑或荒谬的故事,供玩家大声朗读以获取乐趣。 自1950年代发明以来,Mad Libs 一…...

ReactiveSwift模拟登录功能

通过使用ReactiveSwift模拟一个简单的登录功能&#xff0c;该功能如下要求&#xff1a; 账号不能为空密码必须大于6位 登录按钮方可点击 LoginViewModel&#xff1a; import ReactiveSwiftclass LoginViewModel {// 创建两个信号let userName MutableProperty<String&g…...

亲测有效!使用Ollama本地部署DeepSeekR1模型,指定目录安装并实现可视化聊天与接口调用

文章目录 一、引言二、准备工作&#xff08;Ollama 工具介绍与下载&#xff09;2.1 Ollama介绍2.2 Ollama安装 三、指定目录安装 DeepSeek R1四、Chatbox 可视化聊天搭建4.1 Chatbox下载安装4.2 关联 DeepSeek R1 与 Chatbox 的步骤 五、使用 Ollama 调用 DeepSeek 接口5.1 请求…...

【第11章:生成式AI与创意应用—11.3 AI艺术创作的实现与案例分析:DeepArt、GANBreeder等】

凌晨三点的画室里,数字艺术家小美盯着屏幕上的GANBreeder界面——她将梵高的《星月夜》与显微镜下的癌细胞切片图进行混合,生成的新图像在柏林电子艺术展上引发轰动。这场由算法驱动的艺术革命,正在重写人类对创造力的定义。 一、机器视觉的觉醒之路 1.1 数字艺术的三次浪…...

MySQL的基本使用

MySQL 是一个强大且广泛使用的开源关系型数据库管理系统&#xff0c;适用于各种规模的应用程序。无论是初学者还是经验丰富的开发者&#xff0c;掌握 MySQL 的基本操作都是至关重要的。本文将带你了解 MySQL 的基础概念&#xff0c;并通过实例介绍如何执行一些常见的数据库操作…...

WEB安全--SQL注入--PDO与绕过

一、PDO介绍&#xff1a; 1.1、原理&#xff1a; PDO支持使用预处理语句&#xff08;Prepared Statements&#xff09;&#xff0c;这可以有效防止SQL注入攻击。预处理语句将SQL语句与数据分开处理&#xff0c;使得用户输入的数据始终作为参数传递给数据库&#xff0c;而不会直…...

微信小程序image组件mode属性详解

今天学习微信小程序开发的image组件&#xff0c;mode属性的属性值不少&#xff0c;一开始有点整不明白。后来从网上下载了一张图片&#xff0c;把每个属性都试验了一番&#xff0c;总算明白了。现总结归纳如下&#xff1a; 1.使用scaleToFill。这是mode的默认值&#xff0c;sc…...

大模型炼丹基础--GPU内存计算

一、摘要 选择合适的GPU对成本和效率都至关重要&#xff0c;合理分析GPU 二、硬件计算基础 1 个字节可以表示零&#xff08;00000000&#xff09;和 255&#xff08;11111111&#xff09;之间的数字 模型参数常用的数据类型如下&#xff1a; float&#xff08;32 位浮点&a…...

istio入门篇(一)

一、背景 一直以来“微服务”都是一个热门的词汇&#xff0c;在各种技术文章、大会上&#xff0c;关于微服务的讨论和主题都很多。对于基于 Dubbo、SpringCloud 技术体系的微服务架构&#xff0c;已经相当成熟并被大家所知晓&#xff0c;但伴随着互联网场景的复杂度提升、业务…...

Ubuntu 24.04.1 LTS 本地部署 DeepSeek 私有化知识库

文章目录 前言工具介绍与作用工具的关联与协同工作必要性分析 1、DeepSeek 简介1.1、DeepSeek-R1 硬件要求 2、Linux 环境说明2.1、最小部署&#xff08;Ollama DeepSeek&#xff09;2.1.1、扩展&#xff08;非必须&#xff09; - Ollama 后台运行、开机自启&#xff1a; 2.2、…...

沃德校园助手系统php+uniapp

一款基于FastAdminThinkPHPUniapp开发的为校园团队提供全套的技术系统及运营的方案&#xff08;目前仅适配微信小程序&#xff09;&#xff0c;可以更好的帮助你打造自己的线上助手平台。成本低&#xff0c;见效快。各种场景都可以自主选择服务。 更新日志 V1.2.1小程序需要更…...

Visual Studio Code使用ai大模型编成

1、在Visual Studio Code搜索安装roo code 2、去https://openrouter.ai/settings/keys官网申请个免费的配置使用...

工业软件测试方案

一、方案概述 本测试方案致力于全面、系统地评估工业仿真软件的综合性能&#xff0c;涵盖性能表现、功能完整性以及用户体验层面的易用性。同时&#xff0c;将其与行业内广泛应用的MATLAB进行深入的对比分析&#xff0c;旨在为用户提供极具价值的参考依据&#xff0c;助力其在…...

红队视角出发的k8s敏感信息收集——Kubernetes API 扩展与未授权访问

针对 Kubernetes API 扩展与未授权访问 的详细攻击视角分析&#xff0c;聚焦 Custom Resource Definitions (CRD) 和 Aggregated API Servers 的潜在攻击面及利用方法&#xff1a; ​ 攻击链示例 1. 攻击者通过 ServiceAccount Token 访问集群 → 2. 枚举 CRD 发现数据库配…...

一种 SQL Server 数据库恢复方案:解密、恢复并导出 MDF/NDF/BAK文件

方案特色 本方案可以轻松恢复和导出SQL数据库&#xff1a;MDF、NDF 和 BAK 文件。 恢复和导出SQL数据库&#xff1a;主&#xff08;MDF&#xff09;&#xff0c;辅助&#xff08;NDF&#xff09;和备份&#xff08;BAK&#xff09;文件分析 SQL Server LOG 数据库事务日志将 …...

Pygame中自定义事件处理的方法2-1

1 Pygame事件处理流程 Pygame中的事件处理流程如图1所示。 图1 Pygame中事件处理流程 系统事件包括鼠标事件和键盘事件等&#xff0c;当用户点击了鼠标或者键盘时&#xff0c;这些事件会自动被放入系统的事件队列中。用户自定义事件需要通过代码才能被放入事件队列中。Pygame…...

langchain学习笔记之消息存储在内存中的实现方法

langchain学习笔记之消息存储在内存中的实现方法 引言背景消息存储在内存的实现方法消息完整存储&#xff1a;完整代码 引言 本节将介绍 langchain \text{langchain} langchain将历史消息存储在内存中的实现方法。 背景 在与大模型交互过程中&#xff0c;经常出现消息管理方…...

HarmonyOS组件之Tabs

Tabs 1.1概念 Tabs 视图切换容器&#xff0c;通过相适应的页签进行视图页面的切换的容器组件每一个页签对应一个内容视图Tabs拥有一种唯一的子集元素TabContent 1.2子组件 不支持自定义组件为子组件&#xff0c;仅可包含子组件TabContent&#xff0c;以及渲染控制类型 if/e…...

【C++】基础入门(详解)

&#x1f31f; Hello&#xff0c;我是egoist2023&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; 目录 输入&输出 缺省参数(默认参数) 函数重载 引用 概念及定义 特性及使用 const引用 与指针的关系 内联inline和nullptr in…...

bps是什么意思

本文来自DeepSeek "bps" 是 "bits per second" 的缩写&#xff0c;表示每秒传输的比特数&#xff0c;用于衡量数据传输速率。1 bps 即每秒传输 1 比特。 常见单位 bps&#xff1a;比特每秒 Kbps&#xff1a;千比特每秒&#xff08;1 Kbps 1,000 bps&am…...

OceanBase使用ob-loader-dumper导出表报ORA-00600

执行下面的语句导出表报错&#xff0c;同样的语句之前都没有报错。 ob-loader-dumper-4.2.8-RELEASE/bin/obdumper -h xxx.xxx.xxx.xxx -P 2883 -p 密码 --column-splitter| --no-sys-t gzuat_ss#ob8&#xff08;集群&#xff09; -D 数据库名 --cut --table teacher --no-ne…...

JUC并发总结一

大纲 1.Java集合包源码 2.Thread源码分析 3.volatile关键字的原理 4.Java内存模型JMM 5.JMM如何处理并发中的原子性可见性有序性 6.volatile如何保证可见性 7.volatile的原理(Lock前缀指令 + 内存屏障) 8.双重检查单例模式的volatile优化 9.synchronized关键字的原理 …...

hive:分区>>静态分区,动态分区,混合分区

分区表 使用场景&#xff1a;数据量庞大且经常用来做查询的表 特点&#xff1a;将数据分别存储到不同的目录里 优点&#xff1a;避免全盘扫描&#xff0c;提高查询效率 分区的类型 它们的默认值分别是: false, strict, 要求至少有一个静态分区列&#xff0c;而 nonstr…...

深入解析PID控制算法:从理论到实践的完整指南

前言 大家好&#xff0c;今天我们介绍一下经典控制理论中的PID控制算法&#xff0c;并着重讲解该算法的编码实现&#xff0c;为实现后续的倒立摆样例内容做准备。 众所周知&#xff0c;掌握了 PID &#xff0c;就相当于进入了控制工程的大门&#xff0c;也能为更高阶的控制理论…...

linux--关于GCC、动态库静态库

gcc和g的异同 他们是不同的编译器&#xff0c; 在linux中&#xff0c;生成可执行文件不像和windows一样。 linux中是以**.out作为可执行文件**的 无论是什么系统&#xff0c;生成可执行文件分为4步&#xff1a; 预处理–>编译–>汇编–>链接。 从.c/.cpp–>.i文件…...

matlab汽车动力学半车垂向振动模型

1、内容简介 matlab141-半车垂向振动模型 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...

Pygame中自定义事件处理的方法2-2

在《Pygame中自定义事件处理的方法2-1》中提到了处理自定义事件的方法。通过处理自定义事件&#xff0c;可以实现动画等效果。 1 弹跳小球程序 通过处理自定义事件&#xff0c;可以实现弹跳小球程序&#xff0c;如图1所示。 图1 弹跳小球程序 2 弹跳小球程序原理 实现弹跳小…...

B. Longest Divisors Interval

time limit per test 2 seconds memory limit per test 256 megabytes Given a positive integer nn, find the maximum size of an interval [l,r][l,r] of positive integers such that, for every ii in the interval (i.e., l≤i≤rl≤i≤r), nn is a multiple of ii. …...

什么是服务的雪崩、熔断、降级的解释以及Hystrix和Sentinel服务熔断器的解释、比较

1.什么是服务雪崩&#xff1f; 定义&#xff1a;在微服务中&#xff0c;假如一个或者多个服务出现故障&#xff0c;如果这时候&#xff0c;依赖的服务还在不断发起请求&#xff0c;或者重试&#xff0c;那么这些请求的压力会不断在下游堆积&#xff0c;导致下游服务的负载急剧…...

从驾驶员到智能驾驶:汽车智能化进程中的控制与仿真技术

在汽车技术持续演进的历程中&#xff0c;人类驾驶员始终是一个极具研究价值的智能控制系统“原型”。驾驶员通过视觉感知、行为决策与操作执行的闭环控制&#xff0c;将复杂的驾驶任务转化为车辆的实际动作&#xff0c;同时动态适应道路环境的变化。这一过程不仅体现了高度的自…...

mysql和minio

在现代应用架构中&#xff0c;Word 文档、PPT 等文件通常存储在对象存储服务&#xff08;如 MinIO&#xff09;中&#xff0c;而不是直接存储在关系型数据库&#xff08;如 MySQL&#xff09;中。以下是具体的分工和原因&#xff1a; 为什么选择对象存储&#xff08;如 MinIO&a…...

java练习(24)

PS:练习来自力扣 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&am…...

Android的Activity生命周期知识点总结,详情

一. Activity生命周期 1.1 返回栈知识点 二. Activity状态 2.1 启动状态 2.2 运行状态 2.3 暂停状态 2.4 停止状态 2.5 销毁状态 三. Activity生存期 3.1 回调方法 3.2 生存期 四. 体验Activity的生命周期 五. Activity被回收办法 引言&#xff1a; 掌握Acti…...

STM32——HAL库开发笔记19(串口中断接收实验)(参考来源:b站铁头山羊)

本实验&#xff0c;我们以中断的方式使得串口发送数据控制LED的闪烁速度&#xff0c;发送1&#xff0c;慢闪&#xff1b;发送2&#xff0c;速度正常&#xff1b;发送3&#xff0c;快闪。 一、电路连接图 二、实现思路&CubeMx配置 1、实现控制LED的闪烁速度 uint32_t bli…...

基于腾讯云TI-ONE 训练平台快速部署和体验 DeepSeek 系列模型

引言 在前两篇文章中&#xff0c;我们通过腾讯云的HAI部署了DeepSeek-R1&#xff0c;并基于此进行了一系列实践。 腾讯云HAI DeepSeek 腾讯云AI代码助手 &#xff1a;零门槛打造AI代码审计环境 基于腾讯云HAI DeepSeek 快速开发中医辅助问诊系统 这些尝试不仅帮助我们理解…...

python的类装饰器

装饰器不仅可以用于函数&#xff0c;还能作用于类。将装饰器应用于类时&#xff0c;其核心原理与作用于函数类似&#xff0c;都是通过接收一个类作为输入&#xff0c;然后返回一个新的类或者修改后的原类&#xff0c;以此来为类添加额外的功能 简单的类装饰器 def add_method…...

C++17中的LegacyContiguousIterator(连续迭代器)

文章目录 特点内存连续性与指针的兼容性更高的性能 适用场景与C接口交互高性能计算 支持连续迭代器的容器示例代码性能优势缓存局部性指针算术优化 注意事项总结 在C17标准里&#xff0c;LegacyContiguousIterator&#xff08;连续迭代器&#xff09;是一类特殊的迭代器。它不仅…...

Linux-文件IO

1.open函数 【1】基本概念和使用 #include <fcntl.h> int open(const char *pathname&#xff0c;int flags); int open(const char *pathname&#xff0c;int flags&#xff0c;mode_t mode); 功能: 打开或创建文件 参数: pathname //打开的文件名 f…...

DeepSeek-R1 + Cherry Studio 本地部署打造个人 AI 知识库

ChatGPT 爆火的时候&#xff0c;我心里就燃起了一个想法&#xff1a;打造一个专属于自己的AI知识库&#xff0c;它就像我的第二大脑一样&#xff0c;能记住我生活里的点点滴滴。 我随口一问“去年5月我做了什么”&#xff0c;它不仅能精准找到记录&#xff0c;还能帮我回忆起那…...

《红色警戒:兵临城下》 游戏软件安装步骤与百度网盘链接

软件简介&#xff1a; 《红色警戒&#xff1a;兵临城下》&#xff08;Command & Conquer: Red Alert&#xff09;是一款经典的即时战略游戏&#xff0c;由Westwood Studios开发&#xff0c;于1996年首次发行。它是《命令与征服》系列的衍生作品&#xff0c;以其独特的世界…...

25/2/16 <算法笔记> DirectPose

DirectPose 是一种直接从图像中预测物体的 6DoF&#xff08;位姿&#xff1a;6 Degrees of Freedom&#xff09;姿态 的方法&#xff0c;包括平移和平面旋转。它在目标检测、机器人视觉、增强现实&#xff08;AR&#xff09;和自动驾驶等领域中具有广泛应用。相比于传统的位姿估…...

第32周:文献阅读

目录 摘要 Abstract 文献阅读 问题引入 研究问题 研究意义 研究方法 集成方法 随机森林&#xff08;RF&#xff09; 支持向量机&#xff08;SVM&#xff09; 简单循环神经网络&#xff08;SimpleRNN&#xff09; 长短期记忆网络&#xff08;LSTM&#xff09; 创…...

Ollama 开发指南

文章来源&#xff1a;开发指南 - Ollama中文文档|Ollama官方文档 安装先决条件&#xff1a; GOC/C 编译器&#xff0c;例如 macOS 上的 Clang、TDM-GCC &#xff08;Windows amd64&#xff09; 或 llvm-mingw &#xff08;Windows arm64&#xff09;、Linux 上的 GCC/Clang。…...

【deepseek与chatGPT辩论】辩论题: “人工智能是否应当具备自主决策能力?”

探讨辩论题 这个提案涉及创建一个精确的辩论题目&#xff0c;旨在测试deepseek的应答能力。 创建辩论题目 提议设计一个辩论题目以测试deepseek的应答能力。希望这个题目具有挑战性并能够测量其回应质量。 好的&#xff0c;来一道适合深度学习的辩论题&#xff1a; 辩论题&…...

神经网络常见激活函数 9-CELU函数

文章目录 CELU函数导函数函数和导函数图像优缺点pytorch中的CELU函数tensorflow 中的CELU函数 CELU 连续可微指数线性单元&#xff1a;CELU&#xff08;Continuously Differentiable Exponential Linear Unit&#xff09;,是一种连续可导的激活函数&#xff0c;结合了 ELU 和 …...