C/C++ 字符串处理总结

string 和 char* 的互相转换

通常情况下,用 string 操作会更加的方便,这里是std::string的相关函数。由 char* 转 string 非常的方便,直接赋值或者用std::string 的构造函数,详见这里learncpp.com 。由 string 转 char* 一般有两种办法:(1) 利用 std::string::copy() 函数;(2) 先用 std::string::c_str() 把string 转为 const char*, 然后利用 strcpy() 函数拷贝到 char* 中。一个例子如下:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, world!";
    char ps[20];                  // ps[] 某种程度类似于 const char*
    strcpy(ps, str.c_str());      // str.c_str() 返回值 const char*
    ps[str.length()] = '\0';      // 或者 *(ps + str.length()) = 0;

    char *p = (char*)malloc(20);
    str.copy(p, str.length(), 0);   // 可以指定区间,前闭后开
    p[str.length()] = '\0';         // 字符'\0' 就是 0

    cout << ps << endl << p << endl;
    free(p);

    char* h = "freedom";
    string h2(h);                  // 或者 string h2 = h;
    cout << h2 << endl;

    return 0;
}

char* 和 int, float 等的格式化转换

从字符串中提取指定类型数字或子串,这种情形也是非常的常见。大部分的情形都可以用sscanf()sprintf() 这两个函数来实现,如果要求复杂,那么就用正则库或自己手写自动机。一个例子如下:

#include <iostream>
#include <string>
#include<stdio.h>

int main() {
    // 从字符串中提取数字
    char* p = "192.168.1.1";
    int a[4];
    sscanf(p, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
    std::cout << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << "\n";

    // 从字符串中提取数字、子串
    char* p2 = "170 60 Alice";
    int height, weight;
    char name[20];
    sscanf(p2, "%d %d %s", &height, &weight, name);
    std::cout << name << " height: " << height << " weight: " << weight << "\n";

    // 浮点型数字转字符串,并四舍五入保留指定位数小数
    double pi = 3.1415;
    char str[50];
    sprintf(str, "%s %.3f", "pi is:", pi);
    std::cout << str << "\n";  // 输出 3.142

    return 0;
}

介绍一下 format 参数的用法,int sscanf ( const char * s, const char * format, ...); ,其中参数 format 的用法和 scanf() 函数中用法是一样的。和正则表达式有那么一点点的类似。
format可为一个或多个{%[*][width][{h|l|L}]type|''|'\t'|'\n'|非%符号}格式转换符。集合中{a|b|c}表示格式符a、b、c任选其一。以中括号括起来的格式符可选。%与type为必选,所有格式符必须以%开头。一些规则:

  • 赋值抑制符*表明按照随后的转换符指示来读取输入,但将其丢弃不予赋值(跳过)。抑制符无需相应的指针可变参数,该转换也不计入函数返回的成功赋值次数。%*[width][{h|l|L}]type 表示满足该条件的字符被过滤掉,不会向目标参数中赋值。
  • width表示最大读取宽度。当读入字符数超过该值,或遇到不匹配的字符时,停止读取。多数转换丢弃起始的空白字符。这些被丢弃的字符及转换结果添加的空结束符'\0'均不计入最大读取宽度。
  • {h|l|L}为类型修饰符。h 指示输入的数字数值以 short int 或 unsigned short int类型存储;hh 指示输入以 signed char 或 unsigned char 类型存储。l(小写L) 指示输入以 long int、unsigned long int 或 double 类型存储,若与 %c 或 %s 结合则指示输入以宽字符或宽字符串存储;ll 等同 L。L指示输入以long long类型存储。
  • type 为类型转换符,如 %s、%d 。

此外还有字符集合规则,有点儿像正则表达式:

  • %[]:字符集合。[]表示指定的字符集合匹配非空的字符序列;^则表示过滤。该操作不会跳过空白字符(空格、制表或换行符),因此可用于目标字符串不以空白字符分隔时。[]内可有一到多个非^字符(含连字符-),且无顺序要求。%[a-z] 表示匹配a到z之间的任意字符,%[aB-]匹配a、B、-中的任一字符;
  • %[^a]则匹配非a的任意字符,即获取第一个a之前的(不为a的)所有字符。^可作用于多个条件,如^a-z=表示^a-z且^=(既非小写字母亦非等号)。使用[]时接收输入的参数必须是有足够存储空间的 char、signed char 或unsigned char数组。[] 也是转换符,故 %[] 后无 s。
  • n:至此已读入值(未必赋值)的等价字符数,该数目必须以 int 类型存储,并不是很常用。

举例:

源字符串 format 匹配后
hello %s hello
hello, world %s hello,
hello, world %[a-z] hello
12345helloWORLD %*[1-9]%[a-z] hello
IpAddr=10.46.44.40 %*[^=]=%s 10.46.44.40
email:[email protected] %*[^:]:%s [email protected]

你可能感兴趣的:(C++,sprintf,String,sscanf)