Python与C++语法比较--字符串篇

时间:2023-01-24 07:56:16



tags: C++ Python

写在前面

刷lc从Python转向C++, 不只是语法层面, 还要改变很多的API, 这次记录一下C++和Python在字符串方面的一些区别, 供参考.

基本区别

Python字符串是不可变类型, 而C++的String为容器(本质上是一个类的别名, 说容器有点不合适, 因为容器内的元素类型已经被指定为​​char​​), 可变类型.

C++

先说一下字符, 是指​​char​​​类型, 其本质上也是int类型(​​0~127​​的ASCII字符, 存在隐式类型转换)

using string = std::basic_string<char>;  // string其实是一个类型别名

如果不需要一般的字符串操作, 可以使用​​vector<char>​​​, 是一种比较纯粹的字符数组类型, 资源占用较少. 并且C++17新增了一种叫做​​string_view​​​的类型, 用起来比​​string​​轻量, 下面是罗剑锋老师给出的描述.

string它确实有点“重”,大字符串的拷贝、修改代价很高,所以我们通常都尽量用 const string&,但有的时候还是无法避免(比如使用 C 字符串、获取子串)。如果你对此很在意,就有必要找一个“轻量级”的替代品。

在 C++17 里,就有这么一个完美满足所有需求的东西,叫 string_view。顾名思义,它是一个字符串的视图,成本很低,内部只保存一个指针和长度,无论是拷贝,还是修改,都非常廉价。

Python

字符串是不可变类型, 并且转换成ASCII码的话需要额外的内置函数:

chr(97) # 'a'
ord('a') # 97

字符串创建

Python

s1='1'
s2='abc'
s3="45"
s4=r"D:\Desktop"

单双引号都可以, 并且支持原生(raw)字符串.

小坑:

原生字符串不支持单字符, 即​​s=r'\'​​​这样的写法是会报错的, 只能老老实实转义:​​s='\\​​.

C++

string s1="123";
// string s2='1';// error
string s3{"abc"}; //initializer_list, C++11

单引号和双引号并不能混用, 需要注意单引号只能表示单一字符, ​​char​​​类型, 而双引号表示字符串类型(​​char*​​​), 除非使用​​string​​​以及相关构造函数, 否则默认的类型为​​const char*​​, 例如:

void t1() {
auto s1 = "abc";
cout << typeid(s1).name() << endl; // PKc

auto s2 = "bcd"s; // 字符串字面量C++14
cout << typeid(s2).name() << endl;
string s3 = "bcd";
cout << typeid(s3).name() << endl;
/*NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE*/
}

并且C风格的字符串中双引号之间可以合并的语法也被C++的​​string​​延续了下来.

void t2() {
string s1 =
"abc"
"ac";
cout << s1 << endl;
/* string s2 = 'a' 'b'; // error */
}

主要操作

操作

Python方法

C++方法

​s1​​​中查找​​s2​

​s1.find(s2)​​,

找到返回索引, 否则返回-1

​s1.find(s2)​​, 找到返回索引,

否则返回​​string::npos​

取子串​​[1,5]​

​s[1:6]​​, 左闭右开区间取值

​s.substr(1, 5)​​表示从索引1开始取,

取包括1在内的5个字符

连接字符串

​s1​​​和​​s2​

加号或者​​+=​​连接

加号或者​​+=​​连接

字符串比较

字典序比较, 使用比较运算符

字典序比较, 使用比较运算符

检查字符

条件

Python

(成员函数,可针对字符串)

C++

(全局函数,只针对字符)

是否为数字

​s.isdigit()​

​isdigit(c)​

是否为字母

​s.isalpha()​

​isalpha(c)​

是否为小写字母

​s.islower()​

​islower(c)​

是否为大写字母

​s.isupper()​

​isupper(c)​

是否为字母或数字

​s.isalnum()​

​isalnum(c)​

是否为十六进制字符(​​0~F​​)

-

​isxdigit(c)​

转换字符大小写:

转换方向

Python(成员函数)

C++(全局函数)

大写->小写

​s.lower()​

​static_cast<char>(tolower(c))​

小写->大写

​s.upper()​

​static_cast<char>(toupper(c))​

C++

#include <cctype>

void t1() {
char c1 = 'a';
cout << islower(c1) << endl; // 1
char c2 = 'N';
cout << isupper(c2) << endl; // 1
char c3 = '0';
cout << isnumber(c3) << endl; // 1
char c4 = '0';
cout << isalnum(c4) << endl; // 1
char c5 = 'g';
cout << isxdigit(c5) << endl; // 0
}

void t2() {
char c1 = 'a';
/* cout << (char)toupper(c1) << endl; // A */
cout << static_cast<char>(toupper(c1)) << endl; // A
char c2 = 'A';
cout << (char)tolower(c2) << endl; // a
}

格式化输出

这部分不是严格的字符串方面, 但是也有值得对比的点.

C++当然要用最具C++味道的​​cout​​​了(虽然名声不好, 但是在泛型方面的支持还是比​​printf()​​​方便不少, 注意一下别和左移运算符用混了就行), 而Python就是一个​​printf()​​吃遍天.

输出的内容

Python

C++

字符串

​print(s)​

​cout<<s<<endl;​

二进制整数(字符串形式输出)

​print(bin(x))​

​cout<<bitset<>​

八进制整数

​print(oct(x))​

​cout<<oct<<x<<endl;​

十六进制整数(地址值)

​print(hex(x))​

​cout<<hex<<x<<endl;​

整数格式化(指定对齐方式和位数)

Python3.6支持的​​f-string​​​​print(f"{123:0<6}")​

​cout << setfill('0')​​​​<< setw(6) << left​

​<< 123 << endl;​

浮点数格式化输出(指定小数点后4位)

​print(f"{1.2:.4f}")​

​cout << fixed​​​​<< setprecision(4)​

​<< 3.14159 << endl;​

参考:
​​​Formatting Output in C++ (niu.edu)​​;

C++

两种方法.

#include<sstream>
// 使用字符流. (可以定制)
void t3() {
/* basic_ostringstream<char> oss; */
ostringstream oss;
// 默认是right
oss << setfill('0') << setw(5) << left << 123;
cout << oss.str() << endl;
// 可定制
cout << oss.str().insert(3, "-").insert(5, "-") << endl;
/* 12300 */
/* 123-0-0 */
}
// 直接输出
void t4() {
// 默认是right
cout << setfill('0') << setw(5) << left << 123 << endl;
/* 12300 */
}
// 浮点数
void t5() {
cout << setprecision(3) << 3.14159 << endl; // 3.14,总位数
cout << fixed << setprecision(3) << 3.14159 << endl; // 3.142,小数点后位数,支持四舍五入
}

Python

print(f"{123:0<6}") # 123000
print(f"{1.23456:.4f}") # 支持四舍五入, 1.2346

字符流刷新

这算是一个比较小的主题, 但是也很常用. 一个比较常见的例子就是终端命令行程序中的进度条旋转, 使用字符流的输出刷新​​flush​​就可以完成.

下面是Python和C++的实现方式, 需要知道的另外一个点就是​​\r​​表示光标移动到开头, 这同时也是进度条旋转的关键.

from time import sleep

str_lst = ["-", "\\", "|", "/", "-"]

for i in range(100):
sleep(0.5)
print(f"{str_lst[i%4]} process: {i}%\r", flush=True, end="")


下面是C++版本的:

#include <unistd.h>
#include <string>
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
string str{R"(-\|/-)"s};
int n{100};
while (n--) {
usleep(200 * 1000); // 微秒
cout << str[n % 4] << " process:" << 100 - n << "%\r" << flush;
}
return 0;
}


类型转换

转换方向

Python函数

C++函数

字符串->整数

​int()​​,

支持不同数制(​​base​​参数)

​stoi()​​​, ​​stol()​​​, ​​stoll()​

字符串->浮点数

​eval()​

​stof()​​​, ​​stod()​

浮点数/整数->字符串

​str()​

​to_string()​

Python的字符串转换还是相当方便的, 并且支持浮点数

Python

int('1011', base=2) # 11

C++

void t1() {
auto a = "123"s;
auto b = "12.3"s;
cout << stoi(a) << endl;
cout << stod(b) << endl;
/* 123 */
/* 12.3 */
}

小结

暂时先总结这么多, 之后刷题遇到再说.