洛谷评测环境关于非传统题目中文字符(串)处理、操作的说明
__wenziyi__ · · 算法·理论
阅读提示:本文所提到的中文字符均为 UTF-8 编码格式。
导语:
洛谷是一个致力于为编程爱好者提供清爽、快捷的编程体验,集在线测评、学习于一体,拥有强大社区功能的网络平台。在这里,你会遇到形形色色的编程习题,其中不乏有一些非传统题目需要我们对中文字符(串)进行 IO 或其他操作。为此,本文共分为
① 中文字符(串)的存储格式及大小
一般地,单个英文字符或数字占用的内存大小为 UTF-8 编码,每个汉字及其标点占用
例如下列程序:
char str[] = "Abc12洛谷。";
cout << sizeof(str) << endl;
// 输出 15
样例解释:对于 str 字符串,其中 Abc12 为普通英文字符和数字,每个字符占用 洛谷。 为中文子串,每个字符占用 char 类型字符串末尾的 \0 转义字符,共计
对于 string 类型字符串,其空间大小一般不用 sizeof() 函数直接求出,因为该值在编译时确定,与字符串实际内容无关,故不在此赘述。
② 含有中文字符的字符串长度
求一个字符串的长度,我们经常用到 size()、lengh() 或 strlen() 函数。
类似于字符的存储大小(即占用内存的多少),单个字符所占字符串的长度在数值上与其完全相等,即英文和数字字符占用
例如下列程序:
string str = "Abc12洛谷。"; // 或 char str[] = "Abc12洛谷。";
cout << str.size(); // 或 cout << strlen(str);
// 输出14(5×1+3×3=14)
注意:含有中文字符的字符串长度并不等于字符数!(当然,在纯英文字符串中这个等式是成立的)。
③ 含有中文字符的字符串的 IO 操作
一般情况下,将字符串视为一个整体输出时,含有中文的字符串与普通的字符串没有区别。
例如:
string str; // 或 char str[20];
cin >> str; // 输入 "Abc12洛谷。"
cout << str; // 输出 "Abc12洛谷。"
在上述示例中,若使用 getline() 或 gets() 等函数同样能达到目的。只有在以单个字符为单元输入输出时,两者的区别才会体现。
造成这种情况的主要原因是中/英文字符在字节数和所占字符串长度上的区别。
例如下列错误案例❎:
char s;
s = getchar(); // 或 cin >> s;
// 输入 "三"
putchar(s); // 或 printf("%c",s);
// 输出不可见!
案例解释:对于 char 类型的变量,不管以何种方式进行输入,都只能从缓冲区读入并存储 char 类型的变量所能装下的,因此案例中的输入输出必然会造成数据的丢失。有的同学可能会问,那这种读入方式究竟读到了什么呢?其实也并不是什么也没读到,只是读入了中文字符“三”的一部分,也就是其中的
:::warning[警示]
对于大多数初学者,他们在对中文字符进行处理时很容易将单个汉字直接用字符单引号引起,如 char c='中';。但这种方式其实是错误的,会导致数据的丢失。这是因为在 C/C++ 中,单引号用于表示 char 类型的字符常量,而 char 类型通常只占用 UTF-8 编码的中文字符一般占
例如读入一行字符串:
string str;
getline(cin, str); // 输入 "一二三四五12345"
printf("%s", s.c_str()); // 输出 "一二三四五12345"
抑或换一种输入方式:
string str;
char s;
while ((s=getchar())!='\n') // 输入 "一二三四五。。。"
{
str+=s;
}
cout << str; // 输出 "一二三四五。。。"
当然,若是你实在不嫌麻烦,也可以使用多个字符变量分批多次读入的方式存储中文字符(串),只要不改变输入时字符变量的顺序,将其依次输出同样能满足要求。但若是改变顺序输出,则中文字符的编码将会改变,同样会引发不可预测的错误。
例如:
char a, b, c; // 或 char s[3];
cin >> a >> b >> c; // 或使用 getchar() 函数,又或者 cin >> s[0] >> s[1] >> s[2];
// 输入 "三"
cout << a << b << c; // 或使用 putchar() 函数,又或者 cout << s[0] << s[1] <<s[2];
// 输出 "三"
char a, b, c; // 或 char s[3];
cin >> a >> b >> c; // 或 cin >> s[0] >> s[1] >> s[2];
// 输入 "三"
cout << c << b << a; // 或 cout << s[2] << s[1] <<s[0];
// 输出不可见,引发错误,在 IDE 上甚至无法运行!
④ 有关中文字符的基本知识(中文 ASCII 码)
就像初学字符变量一样,本节将介绍有关中文字符的一些基础知识。
类比于西文字符,中文字符其实也有自己的 ASCII 码。当然,这个 ASCII 码并非针对单个中文字符本身,而是指组成中文字符的字符单元。这句话有点绕,什么意思呢?上文已经提到,每个中文字符占 str[1],str[2] 这样可以直接用数组下标访问到的数据就是字符单元。所以,单个中文字符存储到字符串中后就产生了
例如:
string str;
cin >> str;
// 输入 "洛"
cout << str[0];
// 输出不可见
cout << (int)str[0] <<" "<< (int)str[1] <<" "<< (int)str[2];
// 输出 -26 -76 -101
char a, b, c;
a = -26;
b = -76;
c = -101;
printf("%c%c%c", a, b, c);
// 输出 "洛"
中文字符的 ASCII 码常用来判定其是否为中文字符。
温馨提示:在操作含有中文字符的字符串时,要特别注意不要单独对单个中文字符的单个字符单元进行修改,
⑤ 其它关于中文字符(串)的补充介绍
- 字符串库中自带的的一些字符串处理函数,在中文字符串这里同样适用,如查找子串,删除子串等。使用时只需注意将中文字符的
3 个字符单元整体操作即可。 string类型的2 个中文字符串同样可以用关系运算符“==”、“>”、“<”来比较字典序。char类型的strcmp()函数同理。
例如:
string s1 = "Abc12洛谷。";
string s2 = "Abc12洛谷,";
cout << (s1 == s2) << endl;
// 输出 0
⑥ 非传统题目友情推荐链接
以下是一些含有中文字符操作的非传统题目的链接,方便广大爱好者练练手。
- U546490 自幂数的判断
- U550858 浮点数的运算【升级版】
- U553360 中文输出
- U535472 完全数(完美数)【升级版】
全篇终,