c++怎么读取带有特殊符号的外文文本_char16_t与char32_t应用【附代码】

风晨君_7162

风晨君_7162

2026-03-24

819人浏览

原创

正确路径是用c++宽字符流配合显式编码处理:utf-8用std::codecvt_utf8或utf8cpp转std::u32string,utf-16/32需检测并跳过bom,避免依赖已弃用的std::codecvt。

c++怎么读取带有特殊符号的外文文本_char16_t与char32_t应用【附代码】

读取带特殊符号的外文文本,fopen + char 行不通

Windows 上用 fopen("文件.txt", "r") 读 UTF-8 或 UTF-16 文件,大概率乱码——因为 char 是字节单位,而 Unicode 字符(比如 emoji、德语变音符、日文假名)常占多个字节,且系统默认 ANSI 代码页会强行转码。Linux/macOS 稍好但不保证,尤其遇到 BOM 或混合编码时照样崩。

真正能稳住的路径只有一条:绕过 C 风格 FILE*,改用 C++11 起支持的宽字符流 + 显式编码指定。核心不是“选 char16_t 还是 char32_t”,而是先让文件内容按正确编码解包成 Unicode 码位,再进内存。

  • UTF-8 文件 → 用 std::ifstream 配合 std::codecvt_utf8(C++11~17)或 C++20 的 std::text_encoding(尚未普及)
  • UTF-16 文件(含 BOM)→ 必须用 std::wifstream 或 std::basic_ifstream<char16_t></char16_t>,且手动跳过 BOM
  • UTF-32 文件 → 同理,用 std::basic_ifstream<char32_t></char32_t>,BOM 也要检查并跳过
  • 别碰 std::locale + std::codecvt 组合:C++20 已弃用,GCC/Clang 新版本编译直接报错

char16_t 和 char32_t 不是万能解码器,只是容器

char16_t 存一个 UTF-16 code unit(可能是一个代理对的一半),char32_t 存一个完整的 Unicode scalar value(即一个字符)。它们本身不带编码逻辑——你用 std::basic_ifstream<char16_t></char16_t> 打开文件,只是把每两个字节当一个 char16_t 往里塞,如果文件其实是 UTF-8,结果就是彻底错位。

所以关键在「打开前确认编码」和「打开后处理 BOM」:

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • UTF-16LE 文件开头是 0xFF 0xFE → 读取后跳过前两个字节,再逐个 char16_t 读
  • UTF-16BE 文件开头是 0xFE 0xFF → 同样跳过,但需注意平台字节序(x86 默认小端,char16_t 读出来要 swap)
  • UTF-32 文件开头是 0x00 0x00 0xFE 0xFF(BE)或 0xFF 0xFE 0x00 0x00(LE)→ 跳过 4 字节
  • 没 BOM?别猜。要么强制约定(如项目文档写死“所有输入为 UTF-8”),要么用库检测(如 uchardet),别自己写启发式判断

Windows 下最简可行方案:用 std::wifstream + std::locale(仅限本地宽字符 API 兼容场景)

Windows 控制台和记事本默认保存 UTF-16LE,且 std::wifstream 在 Windows 上原生支持 UTF-16(通过 std::codecvt_utf16<wchar_t></wchar_t>),比硬啃 char16_t 更省事。但注意:wchar_t 在 Windows 是 16 位,在 Linux/macOS 是 32 位,跨平台就废。

实操示例(Windows only):

std::wifstream f(L"test.txt");
f.imbue(std::locale(f.getloc(), new std::codecvt_utf16<wchar_t std::little_endian>));
std::wstring line;
std::getline(f, line); // line 里每个 wchar_t 对应一个 UTF-16 code unit
</wchar_t>
  • 必须用 L"test.txt",否则路径字符串本身就被窄化,中文路径直接打不开
  • std::little_endian 对应 UTF-16LE(记事本默认),若文件是 BE,换 std::big_endian
  • C++20 起这整套 codecvt 被移除,新项目慎用
  • 控制台输出 std::wcout 前记得 std::wcout.imbue(...),否则还是乱码

真正跨平台且面向未来的做法:用第三方库做解码,内存里统一用 std::u32string

标准库对 Unicode 的支持支离破碎,与其在 char16_t/char32_t 之间反复横跳,不如一步到位:用 std::string 读原始字节,交给 utf8cpp 或 icu 解码成 std::u32string(每个 char32_t 是一个完整字符)。这样后续处理(查找、切分、正则)全在标量层面,无代理对烦恼。

例如用 utf8cpp(header-only,轻量):

#include <utf8.h>
std::string raw = read_file_as_bytes("test.txt"); // 自己实现,用 std::ifstream::read
std::u32string u32;
utf8::utf8to32(raw.begin(), raw.end(), std::back_inserter(u32));
// u32[0] 就是第一个 Unicode 字符,不管它是 'a' 还是 '?'
</utf8.h>
  • UTF-8 文件直接喂进去;UTF-16/32 则先用 iconv 或 std::wstring_convert(C++17 前)转成 UTF-8 再进
  • std::u32string 占内存大,但换来的是逻辑清晰——比如 u32.length() 真的就是字符数,不是 code unit 数
  • 别试图用 std::u16string 存“用户看到的字符”,它长度不可靠(代理对算两个 char16_t)
  • 文件编码不确定?先用 file -i test.txt 或 uchardet test.txt 查清,比代码里猜强十倍
事情说清了就结束。最易被忽略的点是:**BOM 不是可选装饰,是编码声明;而 char16_t 和 char32_t 本身不解决编码问题,只提供容器——解码逻辑永远得自己扛**。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

5859

3

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1658

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2484

5

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

5944

49

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2023.11.24

5289

6

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

2024.03.22

7014

16

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2024.04.29

9874

11

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

2025.07.29

5019

17

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.07

5347

13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习