6.1 C/C++ 封装字符串操作

c++,封装,字符串,操作 · 浏览次数 : 12

小编点评

字符串长度为 28 字符串中第一个字符是 'W',在字符串s2中也包含字符 'B',因此停止检验,并返回该字符地址,空字符NULL不包括在内。 字符串中第一个字符是 'D',在字符串s2中也包含字符 'J',因此停止检验,并返回该字符地址,空字符NULL不包括在内。

正文

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

6.1.1 封装字符串操作

字符串与整数: 将字符串转为数值可以使用sscanf()函数,将数值转为字符串可以使用sprintf()函数.

#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
  // int -> string
  char szBuf[32] = { 0 };
  int number = 100;

  sprintf(szBuf, "%d", number);
  std::cout << "字符串: " << szBuf << std::endl;

  // string -> int
  sscanf(szBuf, "%d", &number);
  std::cout << "整数: " << number << std::endl;

  return 0;
}

字符串切割: 模拟实现Split()函数对特定字符串使用特定符号进行的切割,切割后的数据分别放入新的数组中.

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

// 实现字符串切割
int split(char dst[][80], char* str, const char* spl)
{
    int n = 0;
    char* result = NULL;
    result = strtok(str, spl);
    while (result != NULL)
    {
        strcpy(dst[n++], result);
        result = strtok(NULL, spl);
    }
    return n;
}

int main(int argc,char *argv[])
{
    char src_string[] = "what is you name? hello lyshark ?";
    char dst[10][80];

    // 以空格进行切割字符串并将结果存入dst
    int cnt = split(dst, src_string, " ");
    for (int i = 0; i < cnt; i++)
    {
        std::cout << "切割后: " << dst[i] << std::endl;
    }
    return 0;
}

字符串分块: 循环将传入的字符串按照指定长度切片处理,切片后返回到一个二维数组中存储.

#include <iostream>
#include <Windows.h>

using namespace std;

// 实现对字符串指定位置进行剪切
char* Cat(char* buffer, int offset, int length)
{
    char Split[100] = { 0 };
    memset(Split, 0, 100);
    strncpy(Split, buffer + offset, length);
    return Split;
}

// 循环剪切字符串
int CatSplit(char *buf, char len ,OUT char Split[][1024])
{
    int count = 0;

    // 每次剪切len大小
    for (int x = 0; x < strlen(buf); x += len)
    {
        char* ref = Cat(buf, x, len);
        strcpy(Split[count], ref);
        count += 1;
    }
    return count;
}

int main(int argc, char* argv[])
{
    char buf[1024] = "The National Aeronautics and Space Administration";
    char Split[100][1024] = { 0 };

    // 切割并获取切割计数器
    int count = CatSplit(buf, 100, Split);
    std::cout << "切割次数: " << count << std::endl;

    // 输出切割计数器
    for (int x = 0; x < count; x++)
    {
        std::cout << Split[x] << std::endl;
    }
    return 0;
}

字符串过滤: 用户传入一个字符串,以及传入需要过滤的字符,自动过滤掉字符串内的所有过滤字符.

#include <iostream>
#include <windows.h>

// 删除指定字符
void del_char(char Buffer[], char ch)
{
    int i, j;
    for (i = 0, j = 0; *(Buffer + i) != '\0'; i++)
    {
        if (*(Buffer + i) == ch)
        {
            continue;
        }
        else
        {
            *(Buffer + j) = *(Buffer + i);
            j++;
        }
    }
    *(Buffer + j) = '\0';
}

void del_char_list(char Buffer[], char list[], int list_count)
{

    for (int x = 0; x < list_count; x++)
    {
        del_char(Buffer, list[x]);
    }
}

int main(int argc, char* argv[])
{
    char szBuffer[8192] = "[ 192.168.1.1 , root , 123456 , 22 ]";

    char del[3] = { '[',']',' '};

    // 删除列表中的字符
    del_char_list(szBuffer, del,3);

    std::cout << "删除后的数据:" << szBuffer << std::endl;
    return 0;
}

字符串替换: 在一个字符串中查找特定字符串,只要找到自动将其替换为新的字符串.

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

using namespace std;

// C语言版 实现字符串替换
char* str_replace(char* src, char* rep, char* with)
{
    char* index;
    char* result, * tmp, * next;
    int count = 0, len_front;
    int len_with = strlen(with);
    int len_rep = strlen(rep);
    next = src;
    for (count = 0; tmp = strstr(next, rep); ++count)
    {
        next = tmp + len_rep;
    }

    tmp = result = (char*)malloc(strlen(src) + count * (len_rep - len_with) + 1);
    if (!result)
        return NULL;
    while (count--)
    {
        index = strstr(src, rep);
        len_front = index - src;
        tmp = strncpy(tmp, src, len_front) + len_front;
        tmp = strcpy(tmp, with) + len_with;
        src += len_front + len_rep;
    }
    strcpy(tmp, src);
    return result;
}

// C++版
string& replace_all_distinct(string& str, const string& old_value, const string& new_value)
{
    for (string::size_type pos(0); pos != string::npos; pos += new_value.length())
    {
        if ((pos = str.find(old_value, pos)) != string::npos)
            str.replace(pos, old_value.length(), new_value);
        else
            break;
    }
    return str;
}

int main(int argc, char* argv[])
{
    char text[128] = "hello lyshark hello lyshark hello lyshark";
    char* rep = str_replace(text, (char*)"lyshark", (char*)"abcd");
    std::cout << "替换后的字符串: " << rep << std::endl;

    // ---------------------------------------------------------

    string str = "hello lyshark,hello lyshark, hello,lyshark";
    string new_str = replace_all_distinct(str, "world", "lyshark");
    std::cout << "替换后的字符串: " << new_str << std::endl;

    return 0;
}

字符串格式化: 利用可变参数列表,实现类似于Python中的format()函数功能,格式化一段字符串.

#include <iostream>

// 格式化字符串
std::string format_string(const char* format, ...)
{
    std::string::size_type size = 1024;
    std::string buffer(size, '\0');
    char* buffer_p = const_cast<char*>(buffer.data());
    int expected = 0;
    va_list ap;

    while (true)
    {
        va_start(ap, format);
        expected = vsnprintf(buffer_p, size, format, ap);

        va_end(ap);
        if (expected > -1 && expected < static_cast<int>(size))
        {
            break;
        }
        else
        {
            if (expected > -1)
                size = static_cast<size_t>(expected + 1);
            else
                size *= 2;

            buffer.resize(size);
            buffer_p = const_cast<char*>(buffer.data());
        }
    }
    return std::string(buffer_p, expected > 0 ? expected : 0);
}

// 可变参数
void print_args(int count, ...)
{
    va_list arg_ptr;
    va_start(arg_ptr, count);
    
    for (int x = 0; x < count; x++)
    {
        int value = va_arg(arg_ptr, int);
        std::cout << "下标: " << x << " 数值: [ " << value << " ] " << std::endl;
    }
    
    va_end(arg_ptr);
}

int main(int argc,char *argv[])
{
    // 输出元素数
    print_args(9, 1, 2, 3, 4, 5, 6, 7, 8, 9);

    // 格式化并输出
    for (int x = 0; x < 1000; x++)
    {
        std::string ref = format_string("address = 192.168.1.%d --> port = %d", x, x+10);
        std::cout << "生成地址: " << ref << std::endl;
    }

    return 0;
}

字符串去空格: 函数接收字符串指针,并循环去除该字符串中左右两端的空格,回写到原空间.

#include <iostream>
#include <string>

using namespace std;

// 去除字符串首尾的空格
bool trim(char* szStr)
{
  int i = 0, j = 0, iFirst = -1, iLast = -1;
  int iLen = strlen(szStr);
  char szTemp[256] = { 0 };
  
  // 从前往后遍历,获取第一个不为 空格 的下标
  for (i = 0; i < iLen; i++)
  {
    if (' ' != szStr[i])
    {
      iFirst = i;
      break;
    }
  }
  
  // 从后往前遍历,获取第一个不为 空格 的下标
  for (i = (iLen - 1); 0 <= i; i--)
  {
    if (' ' != szStr[i])
    {
      iLast = i;
      break;
    }
  }
  
  // 字符串全为 空格
  if (-1 == iFirst || -1 == iLast)
  {
    return false;
  }
  
  // 获取去除 空格 部分
  for (i = iFirst; i <= iLast; i++)
  {
    szTemp[j] = szStr[i];
    j++;
  }
  szTemp[j] = '\0';
  strcpy(szStr, szTemp);

  return true;
}

int main(int argc, char* argv[])
{
  char szBuffer[4096] = "  hello lyshark  ";
  bool ref = trim(szBuffer);

  std::cout << "去空格后: " << szBuffer << std::endl;

    return 0;
}

字符串与HEX互转: 将一段字符串转为一段十六进制数(字符串格式),或将十六进制数转为字符串.

#include <iostream>
#include <Windows.h>

// 将十六进制字符 转 十进制
int hexCharToValue(const char ch)
{
    int result = 0;
    if (ch >= '0' && ch <= '9')
    {
        result = (int)(ch - '0');
    }
    else if (ch >= 'a' && ch <= 'z')
    {
        result = (int)(ch - 'a') + 10;
    }
    else if (ch >= 'A' && ch <= 'Z')
    {
        result = (int)(ch - 'A') + 10;
    }
    else
    {
        result = -1;
    }
    return result;
}

// 将十进制整数 转 字符
char valueToHexCh(const int value)
{
    char result = '\0';
    if (value >= 0 && value <= 9)
    {
        // 48为ascii编码的0字符编码值
        result = (char)(value + 48);
    }
    else if (value >= 10 && value <= 15)
    {
        // 减去10则找出其在16进制的偏移量,65为ascii的A的字符编码值
        result = (char)(value - 10 + 65);
    }
    return result;
}

// 将一段字符串转换为十六进制
int strToHex(char* ch, char* hex)
{
    int high, low;
    int tmp = 0;
    if (ch == NULL || hex == NULL)
        return -1;
    if (strlen(ch) == 0)
        return -2;

    while (*ch)
    {
        tmp = (int)*ch;

        // 取字符的高4位
        high = tmp >> 4;
        // 取字符的低4位
        low = tmp & 15;

        // 先写高字节
        *hex++ = valueToHexCh(high);
        // 其次写低字节
        *hex++ = valueToHexCh(low);
        ch++;
    }
    *hex = '\0';
    return 0;
}

// 将一段十六进制转为字符串
int hexToStr(char* hex, char* ch)
{
    int high, low;
    int tmp = 0;
    if (hex == NULL || ch == NULL)
        return -1;
    if (strlen(hex) % 2 == 1)
        return -2;

    while (*hex)
    {
        high = hexCharToValue(*hex);
        if (high < 0)
        {
            *ch = '\0';
            return -3;
        }

        // 指针移动到下一个字符上
        hex++;
        low = hexCharToValue(*hex);
        if (low < 0)
        {
            *ch = '\0';
            return -3;
        }
        tmp = (high << 4) + low;
        *ch++ = (char)tmp;
        hex++;
    }
    *ch = '\0';
    return 0;
}

// 将十六进制字符串 转 byte字节码
int hexChartoByte(char* hex, char* byte)
{
    int i, n = 0;
    for (i = 0; hex[i]; i += 2)
    {
        if (hex[i] >= 'A' && hex[i] <= 'F')
            byte[n] = hex[i] - 'A' + 10;
        else
            byte[n] = hex[i] - '0';
        
        if (hex[i + 1] >= 'A' && hex[i + 1] <= 'F')
            byte[n] = (byte[n] << 4) | (hex[i + 1] - 'A' + 10);
        else
            byte[n] = (byte[n] << 4) | (hex[i + 1] - '0');
        ++n;
    }
    return n;
}

// 将单一字符 转 ascii 码
unsigned char ChartoAscii(const unsigned char cha)
{
    unsigned char ascii;
    if ((cha >= 0x0A) && (cha <= 0x0F))
    {
        ascii = cha + 'A' - 10;
    }
    else
    {
        ascii = cha + '0';
    }
    return ascii;
}

int main(int argc, char* argv[])
{
    char hex[1024] = { 0 };
    char str[1024] = { 0 };
    char byte[1024] = { 0 };

    int ref = 0;

    // 实现字符串与十六进制互转
    ref = strToHex((char*)"hello lyshark", hex);
    if (ref == 0)
    {
        std::cout << "字符串 -> Hex: " << hex << std::endl;
    }

    ref = hexToStr(hex, str);
    if (ref == 0)
    {
        std::cout << "Hex -> 字符串: " << str << std::endl;
    }

    ref = hexChartoByte(hex, byte);
    if (ref != 0)
    {
        std::cout << "Hex -> Byte: " << byte << std::endl;
    }

    std::cout << "字符 -> Ascii: " << ChartoAscii('12') << std::endl;
}

字符串实现拼接: 将单独的字符串拼接为连续的字符串,类似于strcat()功能实现.

#include <Windows.h>
#include <iostream>

// 组合字符串
char *join(const char *a, const char *b)
{
  // char *c = (char *)ExAllocatePool(NonPagedPool, strlen(a) + strlen(b) + 1);
  char *c = (char *)malloc(strlen(a) + strlen(b) + 1);

  if (c == NULL)
  {
    return NULL;
  }
  char *tempc = c;
  while (*a != '\0')
  {
    *c++ = *a++;
  }
  while ((*c++ = *b++) != '\0') { ; }
  return tempc;
}

int main(int argc, char *argv[])
{
  char * HttpBuffer;
  char DataBuffer[128] = {0};
  char PostData[128] = { 0 };
  
  HttpBuffer = join("POST /", "www.lyshark.com");
  HttpBuffer = join(HttpBuffer, " HTTP/1.1\n");
  HttpBuffer = join(HttpBuffer, "Host: ");
  HttpBuffer = join(HttpBuffer, "www.baidu.com");
  HttpBuffer = join(HttpBuffer, "\n");
  HttpBuffer = join(HttpBuffer, "Proxy-Connection: keep-alive\n");
  HttpBuffer = join(HttpBuffer, "User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36 SE 2.X MetaSr 1.0\n");
  
  strcpy(PostData, "{a:1,b:2}");
  sprintf(DataBuffer, "Content-Length: %d\n", (int)strlen(PostData));
  HttpBuffer = join(HttpBuffer, DataBuffer);
  HttpBuffer = join(HttpBuffer, "Content-Type: application/x-www-form-urlencoded\n\n");
  HttpBuffer = join(HttpBuffer, PostData);

  printf("%s \n", HttpBuffer);
  return 0;
}

字符串实现模拟字典: 通过使用链表结构模拟实现了Python语言中的字典数据结构的基本操作,与字典操作保持一致.

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <errno.h> 

static int N1 = 30;
static int N2 = 30;

typedef struct Data { char key[30]; char value[30]; }Data;
typedef struct Dict
{
  Data data;
  struct Dict* next;
  size_t size;
}Dict;

errno_t append(Dict* dict, const char* key, const char* value);
errno_t repair(Dict* dict, const char* key, const char* value);

// 初始化
Dict* __init__(Dict* dict)
{
  if (dict == NULL)
  {
    dict = (Dict*)calloc(1, sizeof(Dict));
    dict->size = 0;
  }
  else
    dict->next = NULL;

  return dict;
}

// 删除元素
void clear(Dict* dict, const char* key) 
{
  Dict* q = dict;
  Dict* p = dict->next;

  while (p != NULL)
  {
    if (strcmp((p->data).key, key) == 0)
    {
      q->next = p->next;
      dict->size -= 1;
      free(p);
      return;
    }
    q = p;
    p = p->next;
  }
}

// 按主键查找Key是否存在
Dict* _findkey(Dict* dict, const char* key)
{
  Dict* p = dict->next;

  while (p != NULL)
  {
    if (strcmp((p->data).key, key) == 0)
    {
      return p;
    }
    p = p->next;
  }
  return NULL;
}

// 将记录按姓名字母升序插入链表 
void _insert_n(Dict* dict, Dict* q)
{
  Dict* p = dict;

  while (p->next != NULL && strcmp((p->next->data).key, (q->data).key) < 0)
  {
    p = p->next;
  }
  q->next = p->next;
  p->next = q;
  dict->size += 1;
}

// 释放整个链表空间 
void __destroy__(Dict* dict)
{
  Dict* p = dict;
  while (p->next != NULL)
  {
    p = p->next;
    free(dict);
    dict = p;
  }
  if (p != NULL)
    free(p);
}

// 添加字典元素
errno_t append(Dict* dict, const char* key, const char* value)
{
  Dict* p, * r; _set_errno(0);

  if ((r = _findkey(dict, key)) == NULL)
  {
    // 判断记录是否已存在

    // 申请Dict空间并初始化
    p = (Dict*)calloc(1, sizeof(Dict)); 
    if (p != NULL)
    {
      strcpy_s((p->data).key, N1, key);
      strcpy_s((p->data).value, N2, value);
      _insert_n(dict, p);
    }
  }
  else
  {
    repair(dict, key, value);
  }
  return errno;
}

// 修改字典元素
errno_t repair(Dict* dict, const char* key, const char* value)
{
  Dict* r, * p; p = dict;
  _set_errno(0);
  if ((r = _findkey(dict, key)) != NULL)
  {
    strcpy_s(r->data.key, N1, key);
    strcpy_s(r->data.value, N2, value);
  }
  else
  {
    append(dict, key, value);
  }
  return errno;
}

// 获取字典元素
const char* get(Dict* dict, const char* key)
{
  Dict* p = dict->next;

  while (p != NULL)
  {
    if (strcmp((p->data).key, key) == 0)
    {
      return p->data.value;
    }
    p = p->next;
  }
  return "";
}

// 设置字典
void set(Dict* dict, const char* key, const char* value)
{
  repair(dict, key, value);
}

// 判断key是否存在
bool existkey(Dict* dict, const char* key)
{
  Dict* p = dict->next;
  bool result = 0;
  while (p != NULL)
  {
    if (strcmp((p->data).key, key) == 0)
    {
      result = 1; return p;
    }
    p = p->next;
  }
  return result;
}

// 显示所有记录
void view(Dict* dict)
{
  int i = 0;
  Dict* p = dict->next;

  printf("{");
  while (p != NULL)
  {
    printf("size:%d  %s:%s,", dict->size, (p->data).key, (p->data).value);
    p = p->next;
    i++;
  }
  printf("}\n");
}

int main(int argc, char *argv[])
{
  Dict* dict = NULL;
  dict = __init__(dict);

  // 追加键值对
  append(dict, "address", "192.168.1.1");
  append(dict, "username", "root");
  append(dict, "password", "1233");
  append(dict, "port", "22");

  // 替换预设值
  repair(dict, "password", "123456");
  set(dict, "password", "123456789");

  // 判断并输出
  if (existkey(dict, "address"))
  {
    std::cout << "获取数据: " << get(dict, "address") << std::endl;
    std::cout << "获取数据: " << get(dict, "password") << std::endl;
  }

  // 清理记录
  clear(dict, "address");
  clear(dict, "username");
  clear(dict, "password");
  clear(dict, "port");
  __destroy__(dict);

  return 0;
}

字符串URL编码与解码: 将一段URL字符串进行编码与解码的函数过程实现.

#include <iostream>

// 编码URL
std::string encode_url(const char* url, size_t url_length, bool space2plus)
{
    static char hex[] = "0123456789ABCDEF";
    std::string result(url_length * 3 + 1, '\0');

    int i = 0;
    while (*url != '\0')
    {
        char c = *url++;

        if (' ' == c)
        {
            if (space2plus)
            {
                result[i++] = '+';
            }
            else
            {
                // 新标准将空格替换为加号+
                result[i + 0] = '%';
                result[i + 1] = '2';
                result[i + 2] = '0';
                i += 3;
            }
        }
        else if ((c >= '0' && c <= '9') ||
            (c >= 'a' && c <= 'z') ||
            (c >= 'A' && c <= 'Z') ||
            (c == '-') || (c == '_') ||
            (c == '.') || (c == '~'))
        {
            // RFC 3986标准定义的未保留字符 (2005年1月)
            result[i++] = c;
        }
        else
        {
            // 有符号的c值可能是负数
            result[i + 0] = '%';
            result[i + 1] = hex[static_cast<unsigned char>(c) / 16];
            result[i + 2] = hex[static_cast<unsigned char>(c) % 16];
            i += 3;
        }
    }

    result.resize(i);
    return result;
}

// 解码URL
std::string decode_url(const char* encoded_url, size_t encoded_url_length)
{
    std::string result(encoded_url_length + 1, '\0');

    int i = 0;
    while (*encoded_url != '\0')
    {
        char c = *encoded_url++;

        if (c == '+')
        {
            result[i++] = ' ';
        }
        else if (c != '%')
        {
            result[i++] = c;
        }
        else
        {
            if (!isxdigit(encoded_url[0]) ||
                !isxdigit(encoded_url[1]))
            {
                result[i++] = '%';
            }
            else
            {
                char hex[3];
                hex[0] = encoded_url[0];
                hex[1] = encoded_url[1];
                hex[2] = '\0';

                char x = strtol(hex, NULL, 16);
                result[i++] = x;
                encoded_url += 2;
            }
        }
    }

    result.resize(i);
    return result;
}

int main(int argc, char* argv[])
{
    const char* szUrl = "https://www.lyshark.com/index.php?uid=102";

    std::string encode = encode_url(szUrl, strlen(szUrl), false);
    std::cout << "编码后: " << encode << std::endl;

    std::string decode = decode_url(encode.c_str(), strlen(encode.c_str()));
    std::cout << "解码后: " << decode << std::endl;

    return 0;
}

字符串编码互相转换: 在C++语言中通过多种方式实现wstring/wcharstring字符串之间的相互转换.

#include <iostream>
#include <Windows.h>
#include <comutil.h>  
#include <codecvt>

#pragma comment(lib, "comsuppw.lib")

using namespace std;

// 将string转换成wstring
wstring string2wstring(string str)
{
    wstring result;

    //获取缓冲区大小,并申请空间,缓冲区大小按字符计算  
    int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
    TCHAR* buffer = new TCHAR[len + 1];

    // 多字节编码转换成宽字节编码  
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
    buffer[len] = '\0';

    // 删除缓冲区并返回值  
    result.append(buffer);
    delete[] buffer;
    return result;
}

// 将wstring转换成string
string wstring2string(wstring wstr)
{
    string result;

    //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
    int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
    char* buffer = new char[len + 1];

    //宽字节编码转换成多字节编码
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
    buffer[len] = '\0';

    //删除缓冲区并返回值
    result.append(buffer);
    delete[] buffer;
    return result;
}

// 采用ATL封装_bstr_t => wstring 转string
string ws2s(const wstring& ws)
{
    _bstr_t t = ws.c_str();
    char* pchar = (char*)t;
    string result = pchar;
    return result;
}

// 采用ATL封装_bstr_t => string 转wstring
wstring s2ws(const string& s)
{
    _bstr_t t = s.c_str();
    wchar_t* pwchar = (wchar_t*)t;
    wstring result = pwchar;
    return result;
}

// 将 wchar => string
void WcharToString(std::string& szDst, wchar_t* wchar)
{
    wchar_t* wText = wchar;
    DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);
    char* psText;
    // psText 为 char* 的临时数组 作为赋值给std::string的中间变量
    psText = new char[dwNum];

    WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);
    szDst = psText;
    delete[]psText;
}

int main(int argc, char* argv[])
{
    std::string stringA("hello lyshark");
    std::wstring wstringA(L"hello lyshark");

    // 使用原生API进行转换
    std::wcout << "string -> wstring: " << string2wstring(stringA) << std::endl;
    std::cout << "wstring -> string: " << wstring2string(wstringA) << std::endl;

    // 使用ATL进行转换
    std::wcout << "string -> wstring: " << s2ws(stringA) << std::endl;
    std::cout << "wstring -> string: " << ws2s(wstringA) << std::endl;

    // 使用C++标准库转换
    wstring_convert<codecvt<wchar_t, char, mbstate_t>> converter(new codecvt<wchar_t, char, mbstate_t>("CHS"));
    string narrowStr = converter.to_bytes(wstringA);
    wstring wstr = converter.from_bytes(narrowStr);

    std::cout << "wstring -> string: " << narrowStr << std::endl;

    wcout.imbue(locale("chs"));
    std::wcout << "string -> wstring: " << wstr << std::endl;

    // 将wchar转为string
    WCHAR selfFile[MAX_PATH];
    //获取当前进程路径
    GetModuleFileName(NULL, selfFile, MAX_PATH);

    // 当前程序存放路径
    string Current_Path;
    WcharToString(Current_Path, selfFile);
    std::cout << "wchar -> string: " << Current_Path << std::endl;

    return 0;
}

解析字符串字典: 与模拟Python字典不同,如下是通过C++直接实现了解析字符串格式的文本为字典,能够直接当字典解析.

#include <iostream>
#include <string>
#include <vector>

// 切割字符串
void SplitString(const std::string& s, std::vector<std::string>& vect, const std::string& c)
{
  std::string::size_type pos1, pos2;
  pos2 = s.find(c);
  pos1 = 0;
  while (std::string::npos != pos2)
  {
    vect.push_back(s.substr(pos1, pos2 - pos1));
    pos1 = pos2 + c.size();
    pos2 = s.find(c, pos1);
  }
  if (pos1 != s.length())
    vect.push_back(s.substr(pos1));
}

// 删除左右两边空格
void Del_Trim(std::string& s)
{
  if (s.empty())
  {
    return;
  }
  s.erase(0, s.find_first_not_of(" "));
  s.erase(s.find_last_not_of(" ") + 1);
}

// 删除所有空格
void Del_Space(std::string& res)
{
  int r = res.find('\r\n');
  while (r != std::string::npos)
  {
    if (r != std::string::npos)
    {
      res.replace(r, 1, "");
      r = res.find('\r\n');
    }
  }
  res.erase(std::remove_if(res.begin(), res.end(), std::isspace), res.end());
}

// 删除字符串中的指定符号
void Del_Char(std::string& res ,char ch)
{
  int r = res.find(ch);
  while (r != std::string::npos)
  {
    if (r != std::string::npos)
    {
      res.replace(r, 1, "");
      r = res.find(ch);
    }
  }
  res.erase(std::remove_if(res.begin(), res.end(), std::isspace), res.end());
}

// 传入key返回value
std::string get_value(std::string szDict, std::string key)
{
  // 去掉空格
  Del_Space(szDict);

  // 去掉特殊字符
  Del_Char(szDict, '\'');
  Del_Char(szDict, '{');
  Del_Char(szDict, '}');

  // 先使用逗号切割第一次
  std::vector<std::string> one_split;
  SplitString(szDict, one_split, ",");

  for (int x = 0; x < one_split.size(); x++)
  {
    // 循环切割第二次
    std::vector<std::string> two_split;
    SplitString(one_split[x], two_split, ":");

    // std::cout << "key = " << two_split[0] << " value = " << two_split[1] << std::endl;

    // 寻找key所对应的value
    if (strcmp(two_split[0].c_str(), key.c_str()) == 0)
    {
      return two_split[1];
    }
  }
  return "None";
}

int main(int argc, char* argv[])
{
  std::string szDict = "{'address' : '192.168.1.1' , 'username' : 'root' , 'password' : '123123' , 'port': '22'}";

  std::string address_value = get_value(szDict, "address");
  std::cout << "返回地址: " << address_value << std::endl;

  std::string username_value = get_value(szDict, "username");
  std::cout << "返回用户: " << username_value << std::endl;

  return 0;
}

字符串正反向对比与截取: 实现了字符串反向对比以及截取指定位置字符串对比功能.

#include <windows.h>
#include <iostream>

// 将字符串逆序
char* reverse(char str[])
{
    int n = strlen(str);
    int i;
    char temp;
    for (i = 0; i < (n / 2); i++)
    {
        temp = str[i];
        str[i] = str[n - i - 1];
        str[n - i - 1] = temp;
    }
    return str;
}

// 从字符串src中的count位置出开始复制,复制长度为len
bool strnrcpy(char* src, char &dst, int count, int len)
{
    int str = strlen(src);
    std::cout << str << std::endl;

    for (int x = 0; x < strlen(src); x++)
    {
        if (x >= count)
        {
            strncpy(&dst , src + count + 1, len + 1);
            break;
        }
    }
    return true;
}

int main(int argc, char *argv[])
{
    char szBuf[1024] = "Internet Explorer";
    char szRef[1024] = { 0 };

    // 反向对比字符串
    if (strcmp(reverse(szBuf), "rerolpxE tenretnI") == 0)
    {
        std::cout << "先逆序排列,在对比" << std::endl;
    }

    // 字符串提取位置并对比
    reverse(szBuf);
    bool ref = strnrcpy(szBuf, *szRef, 8, 8);
    if (ref == true)
    {
        std::cout << "提取字符串: " << szRef << std::endl;

        if (strcmp(szRef, "Explorer") == 0)
        {
            std::cout << "数据一致" << std::endl;
        }
    }

  return 0;
}

6.1.2 复制与剪切函数

memset 内存填充: 设置某个范围内每字节的值,通常用来清空结构体或者清空某块内存。

#include <stdio.h>
#include <malloc.h>

// 标准库
void* memset(char* s, int c, size_t n)
{
    const unsigned char uc = c;
    char* su;

    for (su = s; 0 < n; ++su, --n)
        *su = uc;
    return (s);
}

int main(int argc, char* argv[])
{
    // 获取10字节的内存
    char* p = (char*)malloc(sizeof(char) * 10);

    // 将该10字节内存全部初始化为0
    memset(p, 0, sizeof(char) * 10);

    return 0;
}

memcpy 内存拷贝: 函数memcpy从s2指向的对象中复制n个字符到s1指定的对象中。

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

// 标准库
void* memcpy(char* s1, const char* s2, size_t n)
{
    char* su1;
    const char* su2;

    for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n)
    {
        *su1 = *su2;
    }

    return s1;
}

// 自实现
void* _memcpy(char* s1, char* s2, size_t n)
{
    char* start, * src;
    start = s1;
    src = s2;

    while (n > 0 && (*start++ = *src++) != '\0')
        n--;

    while (n-- > 0)
        *start++ = '\0';

    *start = '\0';

    return s1;
}

int main(int argc, char const* argv[])
{
    char text[20] = {0};

    std::cout << "标准库: " << text << " 地址: " << memcpy(text, "hello lyshark", 13) << std::endl;
    std::cout << "自实现: " << text << " 地址: " << _memcpy(text, (char *)"hello lyshark", 13) << std::endl;

    return 0;
}

memmove 内存移动: 函数memmove从s2指向的对象中复制n个字符串到s1指向的对象中。

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

// 标准库
void* memmove(char* s1, const char* s2, size_t n)
{
    char* sc1;
    const char* sc2;

    sc1 = s1;
    sc2 = s2;

    // 如果 sc1 的地址比 sc2 要低,并且两者相处不足 n 字节
    if (sc2 < sc1 && sc1 < sc2 + n)
    {
        // 逆向复制
        for (sc1 += n, sc2 += n; 0 < n; --n)
        {
            *--sc1 = *--sc2;
        }
    }
    else
    {
        // 正向复制
        for (; 0 < n; --n)
        {
            *sc1++ = *sc2++;
        }
    }
    return s1;
}

// 自实现
void* _memmove(char* s1, const char* s2, size_t n)
{
    char* su1;
    const char* su2;
    int i;
    if (s1 < s2 && s2 - s1 < n)
    {
        // 加了 n 忘记减一了
        for (su1 = s1 + n, su2 = s2 + n; n > 0; --n, --su1, --su2)
        {
            *su1 = *su2;
        }
    }
    else
    {
        // i 多余了
        for (i = 0, su1 = s1, su2 = s2; i < n; ++i, ++su1, ++su2)
        {
            *su1 = *su2;
        }
    }
    return s1;
}

int main(int argc, char const* argv[])
{
    char text[20] = {0};

    std::cout << "标准库: " << text << " 地址: " << memmove(text, "hello lyshark", 13) << std::endl;
    std::cout << "自实现: " << text << " 地址: " << _memmove(text, (char *)"hello lyshark", 13) << std::endl;

    return 0;
}

strcpy 字符串拷贝: 把s2指向的串(包括终止的空字符)复制到s1指向的数组中。

#include <stdio.h>

// 标准库
char* strcpy(char* s1, const char* s2)
{
    char* s = s1;

    for (s = s1; (*s++ = *s2++) != '\0'; )
        ;

    return s1;
}

// 自实现
char* _strcpy(char* s1, const char* s2)
{
    char* start = s1;
    while (*s1++ = *s2++)
        ;
    return start;
}

int main(int argc, char const* argv[])
{
    char text[20] = {0};

    strcpy(text, "hello lyshark");
    return 0;
}

strncpy 字符串前N字节拷贝: 把s2指向的串(包括终止的空字符)复制到s1指向的数组中。

#include <stdio.h>

// 标准库
char* (strncpy)(char* s1, const char* s2, size_t n)
{
    char* s;
    
    // 当n不为0 且s2为拷贝完时,复制字符过去
    for (s = s1; 0 < n && *s2 != '\0'; ++s)
        *s++ = *s2++;
    
    // 若n有多出,则补零
    for (; 0 < n; --n)
        *s++ = '\0';
    return s1;
}

// 自实现
char* _strncpy(char* s1, const char* s2, size_t n)
{
    char* start = s1, count = 0;

    while ((count < n) && (*s1 = *s2))
    {
        count++, s1++, s2++;
        // printf("第%d个 已拷贝n", count);
    }

    while (count++ < n)
    {
        *s1++ = '\0';
        // printf("第%d个 已补零n", count);
    }

    return start;
}

int main(int argc, char const* argv[])
{
    char text[20] = {0};

    strncpy(text, "hello lyshark",5);
    _strncpy(text, "hello lyshark", 6);

    return 0;
}

strcat 字符串连接: 函数strcat把s2指向的串(包括终止的空字符)的副本添加到s1指向的串的末尾。

#include <stdio.h>

// 标准库
char* strcat(char* s1, const char* s2)
{
    char* s;
    
    // 指针移动到s1的结尾
    for (s = s1; *s != '\0'; ++s)
        ;
    // 如果s2未结尾则拷贝
    for (; (*s = *s2) != '\0'; ++s, ++s2)
        ;
    return (s1);
}

// 自实现
char* _strcat(char* s1, const char* s2)
{
    char* start = s1;
    while (*s1)
        s1++;
    while (*s1++ = *s2++)
        ;
    return start;
}

int main(int argc, char const* argv[])
{
    char text[20] = "hello ";

    printf("%s \n", _strcat(text, "lyshark"));

    return 0;
}

strncat 字符串连接前N个字节: 函数strncat从s2指向的数组中将最多n个字符(空字符及其后面的字符不添加)添加到s1指向的串的末尾。

#include <stdio.h>

// 标准库
char* strncat(char* s1, const char* s2, size_t n)
{
  char* s;
  
  // 指针移动到s1的结尾
  for (s = s1; *s != '\0'; ++s)
    ;
  
  // 如果s2未结尾则拷贝
  for (; 0 < n && *s2 != '\0'; --n)
    *s++ = *s2++;
  
  // 字符串s1结尾补'\0'
  *s = '\0';
  return (s1);
}

// 自实现
char* _strncat(char* s1, const char* s2, size_t n)
{
  char* start = s1;
  while (*s1)
    s1++;
  while ((0 < n--) && (*s1++ = *s2++))
  {
    ;
    // printf("第%d个 已赋值n", n);
  }

  while (0 < n--)
  {
    *s1++ = '\0';
    // printf("第%d个 已补零n", n);
  }
  return start;
}

int main(int argc, char const* argv[])
{
    char text[20] = "hello ";

  printf("%s \n", strncat(text, "lyshark", 5));
    printf("%s \n", _strncat(text, "lyshark",8));

    return 0;
}

6.1.3 字符串比较函数

strlen 字符串取长度: 字符串长度获取函数,用于获取一段以0结尾的字符串长度。

#include <stdio.h>

// 标准库
int strlen(const char* s)
{
    const char* sc;

    for (sc = s; *sc != '\0'; ++sc)
        ;
    return (sc - s);
}

// 自实现
int _strlen(const char* dest)
{
    const char* start = dest;
    while (*dest)
        dest++;
    return (dest - start);
}

int main(int argc, char const* argv[])
{
    printf("%d", _strlen("hello lyshark"));
    return 0;
}

strcmp 字符串比较: 字符串比较函数,用于比较两个字符串的区别。

#include <stdio.h>

// 标准库
int strcmp(const char* s1, const char* s2)
{
    for (; *s1 == *s2; ++s1, ++s2)
        if (*s1 == '\0')
            return (0);

    return ((*(unsigned char*)s1 < *(unsigned char*)s2) ? -1 : +1);
}

// 自实现
int _strcmp(const char* dest, const char* src)
{
    int res = 0;
    while (res == 0 && *src != '\0')
        res = *dest++ - *src++;
    return res;
}

int main(int argc, char const* argv[])
{
    char text[20] = "hello ";

    if (_strcmp(text, "hello ") == 0)
    {
        printf("相等");
    }
    return 0;
}

strncmp 比较前N个字符: 比较两个字符串的前n个字符。

#include <stdio.h>

// 标准库
int strncmp(const char* s1, const char* s2, size_t n)
{
    for (; 0 < n; ++s1, ++s2, --n)
        if (*s1 != *s2)
            return ((*(unsigned char*)s1 < *(unsigned char*)s2) ? -1 : +1);
        else if (*s1 == '\0')
            return 0;
    return 0;
}

// 自实现
int _strncmp(const char* s1, const char* s2, size_t n)
{
    const char* dest = s1, * src = s2;
    while (n-- > 0 && *dest != '\0')
        if (*dest++ - *src++)
            return *dest - *src;
    return 0;
}

int main(int argc, char const* argv[])
{
    char text[20] = "hello ";

    if (_strncmp(text, "he", 2) == 0)
    {
        printf("相等");
    }

    return 0;
}

memcmp 内存字节比较: 该函数与strcmp类似,区别在于memcmp不会检查字符串是否到结束。

#include <stdio.h>

// 标准库
int memcmp(const char* s1, const char* s2, size_t n)
{
    const char* su1, * su2;

    for (su1 = s1, su2 = su2; 0 < n; ++su1, ++su2, --n)
        if (*su1 != *su2)
            return ((*su1 < *su2) ? -1 : +1);
    return 0;
}

// 自实现
int _memcmp(const char* s1, const char* s2, size_t n)
{
    const char* dest = s1, * src = s2;
    while (n-- > 0)
        if (*dest++ - *src++)
            return *dest - *src;
    return 0;
}

int main(int argc, char const* argv[])
{
    char text[20] = "hello ";

    if (_memcmp(text, "he", 2) == 0)
    {
        printf("相等");
    }

    return 0;
}

strcoll/strxfrm 中文字符串比较: 该函数主要实现中文字符串的比较。

locale.h本地库有关的字符串比较函数,在开始比较之前会按照特定的方式转换字符串然后在进行比较。

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

#define ST_CH       0x00ff
#define ST_STATE    0x0f00
#define ST_STOFF    8
#define ST_FOLD     0x8000
#define ST_INPUT    0x4000
#define ST_OUTPUT   0x2000
#define ST_ROTATE   0x1000
#define _NSTATE     16

/* 类型定义 */
typedef struct {
    const unsigned short* _Tab[_NSTATE];
} _Statab;

/* 声明*/
extern _Statab _Costate, _Mbstate, _Wcstate;

/* type definnitions 类型定义 */
typedef struct {
    unsigned char _State;
    unsigned short _Wchar;
} _Cosave;

/* declarations 声明 */
size_t _Strxfrm(char*, const unsigned char**, size_t, _Cosave*);

/* 设置默认为 0 的本地配置项 */
_Statab _Costate, _Mbstate, _Wcstate;

// _Cosave 存储状态信息
size_t _Strxfrm(char* sout, const unsigned char** psin,size_t size, _Cosave* ps)
{
    // 翻译字符串到可校对的格式
    char state = ps->_State;
    int leave = 0;
    int limit = 0;
    int nout = 0;
    const unsigned char* sin = *psin;
  
  // 宽字节字符累加器
    unsigned short wc = ps->_Wchar;

    for (; ; )
    {
        // 执行状态转换
        unsigned short code;
        const unsigned short* stab;

        if (_NSTATE <= state
            || (stab = _Costate._Tab[state]) == NULL
            || (_NSTATE * UCHAR_MAX) <= ++limit
            || (code = stab[*sin] == 0))
            break;

        state = (code & ST_STATE) >> ST_STOFF;

        if (code & ST_FOLD)
            wc = wc & ~UCHAR_MAX | code & ST_CH;
        if (code & ST_ROTATE)
            wc = wc >> CHAR_BIT & UCHAR_MAX | wc << CHAR_BIT;
        if (code & ST_OUTPUT && ((sout[nout++]
            = code & ST_CH ? code : wc) == '\0'
            || size <= nout))
            leave = 1;
        if (code & ST_INPUT)
            if (*sin != '\0')
                ++sin, limit = 0;
            else
                leave = 1;
        if (leave)
        {
            // 现在返回
            *psin = sin;
            ps->_State = state;
            ps->_Wchar = wc;
            return nout;
        }
    }
  
  // 错误返回
    sout[nout++] = '\0';
    *psin = sin;
    ps->_State = _NSTATE;
    return nout;
}

定义好以上转换过程,就可以进行比较了,函数_strcoll()主要用于比较完整中文字符串,而_strxfrm()则用于比较指定的前几个中文字符。

typedef struct
{
    char buf[32];
    const unsigned char* s1, * s2, * sout;
    _Cosave state;
} Sctl;

static size_t getxfrm(Sctl* p)
{
    size_t i;

    do
    {
        p->sout = (const unsigned char*)p->buf;
        i = _Strxfrm(p->buf, &p->s1, sizeof(p->buf), &p->state);
        if (0 < i && p->buf[i - 1] == '\0')
            return (i - 1);
        else if (*p->s1 == '\0')
            p->s1 = p->s2;
    } while (i == 0);
    return i;
}

// 比较全部中文字符串
int _strcoll(const char* s1, const char* s2)
{
    size_t n1, n2;
    Sctl st1, st2;
    static const _Cosave initial = { 0 };

    st1.s1 = (const unsigned char*)s1;
    st2.s2 = (const unsigned char*)s1;
    st1.state = initial;

    st2.s1 = (const unsigned char*)s2;
    st2.s2 = (const unsigned char*)s2;
    st2.state = initial;

    for (n1 = n2 = 0; ; )
    {
        int ans;
        size_t n;

        if (n1 == 0)
            n1 = getxfrm(&st1);
        if (n2 == 0)
            n2 = getxfrm(&st2);
        n = n1 < n2 ? n1 : n2;
        if (n == 0)
            return (n1 == n2 ? 0 : 0 < n2 ? -1 : +1);
        else if ((ans = memcmp(st1.sout, st2.sout, n)) != 0)
            return ans;

        st1.sout += n, n1 -= n;
        st2.sout += n, n2 -= n;
    }
}

// 指定比较行
size_t _strxfrm(char* s1, const char* s2, size_t n)
{
    size_t nx = 0;
    const unsigned char* s = (const unsigned char*)s2;
    _Cosave state = { 0 };

    while (nx < n)
    {
        // 转化 并 传递
        size_t i = _Strxfrm(s1, &s, n - nx, &state);

        s1 += i, nx += i;
        if (0 < i && s1[-1] == '\0')
            return nx - 1;
        else if (*s == '\0')
            s = (const unsigned char*)s2;
    }
    for (; ; )
    {
        char buf[32];
        size_t i = _Strxfrm(buf, &s, sizeof(buf), &state);

        nx += i;
        if (0 < i && buf[i - 1] == '\0')
            return nx - 1;
        else if (*s == '\0')
            s = (const unsigned char*)s2;
    }
}

int main(int argc, char *argv[])
{
    char hi[] = "中文";

    if (_strcoll(hi, "中文") == 0)
    {
        printf("相等");
    }

    if (_strxfrm(hi, "中", 1) == 0)
    {
        printf("相等");
    }

    return 0;
}

6.1.4 字符串查找函数

memchr 内存中查找: 内存中查找,参数void *适合各种数据类型,不过只能查找一个字节。

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

// 标准库
void *memchr(const void *s, int c, size_t n)
{
    const unsigned char uc = c;
    const unsigned char *su;
 
    for (su = s; 0 < n; ++su, --n)
        if (*su == uc)
            return ((void *)su);
    return (NULL);
}

// 自实现
void *_memchr(const void *s, int c, size_t n)
{
    const unsigned char *pstr = s;
    const unsigned char search = (unsigned char)c;
 
    while(n-- > 0)
    {
        if (*pstr == search)
        {
            return (void *)pstr;
        }
        pstr++;
    }
 
    return NULL;
}
 
int main(int argc, char *argv[])
{
    char *p;
    p = _memchr("hello lyshark", 'w', 8);
    printf("%sn", p);
    return 0;
}

strchr 字符串中查找: 字符串中查找字符,并返回这个字符第一次出现的地址。

#include <stdio.h>
#include <string.h>
 
 // 标准库
char *strchr(const char *s, int c)
{
    const char ch = c;
 
    for (; *s != '\0'; ++s)
        if (*s == '\0')
            return NULL;
    return ((char *)s);
}


// 自实现
char *_strchr(const char *s, int c)
{
    const unsigned char *pstr = s;
    const unsigned char search = (unsigned char)c;
 
    while(*pstr != '\0')
    {
        if (*pstr == search)
        {
            return (char *)pstr;
        }
        pstr++;
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    char *p;
    p = _strchr("hello lyshark", 'o');
    printf("%s", p);
    return 0;
}

strrchr 字符串中反向查找: 字符串反向查找字符,返回这个字符最后一次出现的位置。

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

// 标准库
char *strrchr(const char *s, int c)
{
    const char ch = c;
    const char *sc;
 
    for (sc = NULL; ; ++s)
    {
        if (*s == ch)
            sc = s;
        if (*s == '\0')
            return ((char *)sc);
    }
}

// 自实现
char *_strrchr(const char *s, int c)
{
    const unsigned char *pstr = NULL, search = (unsigned char)c;
 
    do
    {
        if (*s == search)
        {
            pstr = s;
        }
    } while (*s++);
 
    return (char *)pstr;
}

int main(int argc, char *argv[])
{
    char *p;
    p = strrchr("hello lyshark", 'o');
    printf("%s", p);
    return 0;
}

strstr 字符中查找字符串: 字符串中查找字符串,如果能找到则返回其地址找不到则返回NULL。

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

// 标准库
char *strstr(const char *s1, const char *s2)
{
    if(*s2 == '\0')
        return ((char *)s1);
    for( ; (s1 = strchr(s1, *s2)) != NULL; ++s1)
    {
        const char *sc1, *sc2;
 
        for(sc1 = s1, sc2 = s2; ; )
            if(*++sc2 == '\0')
                return ((char *)s1);
            else if(*++sc1 != *sc2)
                break;
    }
    return NULL;
}

// 自实现
char *_strstr(const char *s1, const char *s2)
{
    while ( (s1 = strchr(s1, *s2)) != NULL )
        if(strcmp(s1, s2) == 0)
            return (char *)s1;
        else
            s1++;
    return NULL;
}

int main(int argc, char *argv[])
{
    printf("%s", _strstr("that this think", "think"));
    return 0;
}

strtok 根据标识查找字符串: 通过标识来查找字符串,需要注意的是这个会修改原来字符串的值。

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

char * strtok(char *s1, const char *s2)
{
    char *sbegin, *send;
    static char *ssave = "";
 
    sbegin = s1 ? s1 : ssave;
    // printf("1.sbegin: %sn", sbegin);
    // printf("2.strspn(sbegin, s2): %dn", strspn(sbegin, s2));
    sbegin += strspn(sbegin, s2);
    if (*sbegin == '\0')
    {
        ssave = "";
        return NULL;
    }
 
    // printf("3.sbegin: %sn", sbegin);
    send = sbegin + strcspn(sbegin, s2);
    // printf("4.sbegin: %sn", sbegin);
    // printf("5.send: %sn", send);
     
    if (*send != '\0')
        *send++ = '\0';
 
    ssave = send;
    // printf("6.send: %sn", send);
    return (sbegin);
}
 
int main(int argc, char *argv[])
{
    char input[] = "program,hello,world";
    char *p;
 
    /* 截取到第一个标识符之前 */
    p = strtok(input, "e");
    if(p)
    {
        printf("%sn", p);
    }
    /* 截取第一个标识符之后一段 */
    p = strtok(NULL, "e");
    if(p)
    {
        printf("%sn", p);
    }
 
    // 源字符串被截断
    printf("最后input : %s", input);
    return 0;
}

strspn 范围之内查找: 字符串范围查找,在s1中找s2,从s1的开头依次与s2比较,返回第一个与s2不同的字符下标。

#include <string.h>
#include <stdio.h>
 
// 函数说明 strspn 返回字符串中第一个不在指定字符串中出现的字符下标
size_t _strspn(const char *s1,const char *s2)
{
    const char *sc1 = s1, *sc2 = s2;
 
    for(sc1 = s1, sc2 = s2; *sc1 != '\0'; ++sc1, ++sc2)
        if (*sc2 == '\0')
            return (sc1 - s1);
        else if (*sc1 == *sc2)
            continue;
        else
            break;
    return sc1 - s1;
}

size_t strspn(const char *s1,const char *s2)
{
    const char *sc1, *sc2;
 
    printf("sc2: [%s] ", s2);
 
    for(sc1 = s1; *sc1 != '\0'; ++sc1)
        for (sc2 = s2; ; ++sc2)
            if (*sc2 == '\0')
                return (sc1 - s1);
            else if (*sc1 == *sc2)
                break;
    return (sc1 - s1);
}

int main(int argc, char const *argv[])
{
    char *str = "what do you think about this this program? 1";
    printf("%dn", _strspn(str,"w"));
    printf("%dn", _strspn(str,"what"));
    printf("%dn", _strspn(str,"what "));
    printf("%dn", _strspn(str,"what d"));
    printf("%dn", _strspn(str,"what do"));
    printf("%dn", _strspn(str,"what do "));
    printf("%dn", _strspn(str,"what do y"));
    printf("%dn", _strspn(str,"what do yo"));
    printf("%dn", _strspn(str,"what do you"));
    printf("%dn", _strspn(str,"you"));
    printf("%dn", _strspn(str,"1234567890"));
    return 0;
}

strcspn 范围之外查找: 在字符串s1中搜寻与s2中字符的第一个相同字符,包括结束符NULL,返回这个字符在S1中第一次出现的位置。

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

// 标准库
size_t strcspn(const char *s1,const char *s2)
{
    const char *sc1, *sc2;
 
    for (sc1 = s1; *sc1 != '\0'; ++sc1)
        for(sc2 = s2; *sc2 != '\0'; ++sc2)
            if (*sc1 == *sc2)
                return (sc1 - s1);
    // 返回NULL,即字符串结束
    return (sc1 - s1);
}

int main(int argc, char *argv[])
{
    char *str = "Linux was first developed for 386/486-based pcs. ";
    printf("字符串长度为 %dn", strlen(str));
    printf("%dn", strcspn(str, " "));
    printf("%dn", strcspn(str, "/-"));
    printf("%dn", strcspn(str, "1234567890"));
    printf("%dn", strcspn(str, ""));
    return 0;
}

strpbrk可以理解为找到目标(string)中的字符后中断(break)并返回其地址(pointer),其功能与strcspn相同,区别只是strpbrk返回的是地址。

#include <stdio.h>
#include <string.h>
 
/*
    依次检验字符串s1中的字符,当被检验字符在字符串s2中也包含时
    则停止检验,并返回该字符地址,空字符NULL不包括在内。
*/

// 标准库
char * strpbrk(const char * s1,const char * s2)
{
    const char *sc1, *sc2;
 
    for(sc1 = s1; *sc1 !='\0'; ++sc1)
        for(sc2 = s2; *sc2 !='\0'; ++sc2)
            if(*sc1 == *sc2)
                return ((char *)sc1);
    return NULL;
}
 
int main(int argc, char *argv[])
{
    char *s1="Welcome To Beijing";
    char *s2="BIT";
    char *p;
 
    p = strpbrk(s1,s2);
    if(p)
        printf("%sn",p);
    else
        printf("Not Found!n");
 
    p = strpbrk(s1, "Daj");
 
    if(p)
        printf("%s",p);
    else
        printf("Not Found!n");
 
    return 0;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/feee755.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与6.1 C/C++ 封装字符串操作相似的内容:

6.1 C/C++ 封装字符串操作

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

上周热点回顾(4.22-4.28)

热点随笔: · 上架即封神!3.6k Star 的开源游戏模拟器,Delta 冲上 App Store 免费榜 (削微寒)· DDD领域驱动设计总结和C#代码示例 (Eric zhou)· 见鬼了!我家的 WiFi 只有下雨天才能正常使用... (米开朗基杨)· 他又来了,.net开源智能家居之小米

3.1 C/C++ 使用字符与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

6.1 C++ STL 序列映射容器

Map/Multimap 映射容器属于关联容器,它的每个键对应着每个值,容器的数据结构同样采用红黑树进行管理,插入的键不允许重复,但值是可以重复的,如果使用`Multimap`声明映射容器,则同样可以插入相同的键值。Map中的所有元素都会根据元素的键值自动排序,所有的元素都是一个`Pair`同时拥有实值和键值,Pair的第一个元素被视为键值,第二个元素则被视为实值,Map 容器中不允许两个元素有相

.NET周刊【6月第1期 2024-06-02】

国内文章 一文带你了解.NET能做什么? https://www.cnblogs.com/Can-daydayup/p/18214473 .NET是一个免费、开源、跨平台的开发平台框架,广泛应用于桌面、Web、移动、云服务、游戏、物联网、大数据和人工智能等领域开发。它支持C#、Visual Basi

[转帖]echo 输出不换行-e \c

http://www.my889.com/i/1952 在shell中,echo输出会自动换行。有时候在循环中不希望echo输出换行。代码实现如下: 1 echo -e " \c" # -e 表示开启转义, \c表示不换行 脚本: 1 2 3 4 5 6 7 8 9 #!/bin/bash i=1

.NET周刊【6月第4期 2024-06-23】

国内文章 C#.Net筑基-集合知识全解 https://www.cnblogs.com/anding/p/18229596 .Net中提供了数组、列表、字典等多种集合类型,分为泛型和非泛型集合。泛型集合具有更好的性能和类型安全性。集合的基础接口包括IEnumerator、IEnumerable、I

4.6 C++ Boost 函数绑定回调库

Boost库中提供了函数对象库,可以轻松地把函数的参数和返回值进行绑定,并用于回调函数。这个库的核心就是bind函数和function类。bind函数可以将一个函数或函数对象和其参数进行绑定,返回一个新的函数对象。通过这个新的函数对象,我们就可以将原有的函数或函数对象当做参数传来传去,并可以传递附加的参数,方便实现参数绑定和回调函数。function类用于表示一种特定的函数签名,可以在不知道具体函

.NET周刊【6月第2期 2024-06-09】

国内文章 C#开源实用的工具类库,集成超过1000多种扩展方法 https://www.cnblogs.com/Can-daydayup/p/18230586 文章介绍了一个免费的C#工具类库Z.ExtensionMethods,可以通过NuGet包管理器轻松集成。该库支持.NET Standard

上周热点回顾(6.3-6.9)

热点随笔: · C#开源实用的工具类库,集成超过1000多种扩展方法 (追逐时光者)· RabbitMQ 进阶使用之延迟队列 → 订单在30分钟之内未支付则自动取消 (青石路)· .Net 中间件 - 新开源代码生成器 -ReZero (阿妮亚)· C#.Net筑基-String字符串超全总结 [深