无法忽略文本文件流中的转义字符并存储在 C++ 中的 wchar_t [ ] 中
Unable to ignore the escape characters from a text file stream & store in a wchar_t [ ] in C++
我正在尝试使用 C++ 从文本文件中读取数据并将每行的字符串存储到 wchar_t [] 或 LPCWSTR 中。
(这 2 种数据类型是我正在处理的应用程序的约束。这就是为什么我必须将数据存储在这些数据类型中的原因)
.txt文件中的数据格式,例如:
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
我正在尝试逐行读取数据并将每一行保存为映射的键值对,其中键是LPCWSTR类型或wchar_t[]类型&值是int类型
提取 int 没有问题,但问题出在读取字符串
这是我的代码:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
using namespace std;
int main()
{
wchar_t test1[260];
const char* s = "Hello\ABC\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
wcout<<gr<<L" ";
cout<<percentage<<endl;
}
ifs.close();
}
return 0;
}
但是,它给出了以下输出:
Hello\ABC\DEFa
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
我不明白为什么那个小'a'突然出现在输出的第一行
我希望代码自动处理那些双斜杠,即我希望输出为:
Hello\ABC\DEF
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
如果我可以在 .txt 文件中写入不带双斜杠的条目,并且它们会在不检查任何转义序列的情况下自动处理,那就更好了。但是,由于第 1 点中的问题。 1) 上面有,所以我不确定是否可能
即使在 while 循环的第一行添加 cout<<gr_temp<<endl;
,即使这样也会输出带有双反斜杠的字符串。
我错过了什么或做错了什么?
更新:
此外,当我在每个 while 循环末尾使用语句 m1[gr] = percentage;
将这些键值对添加到 std::map<LPCWSTR,int> m1
时,然后使用 print 语句,它只显示一个元素在地图上。
我的更新代码是:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
#include<map>
using namespace std;
std::unordered_map<LPCWSTR, int> m1;
int main()
{
wchar_t test1[260];
const char* s = "Hello\ABC\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
m1[gr] = percentage;
}
ifs.close();
}
for (auto i = m1.begin(); i != m1.end(); i++) {
wcout<< i->first << L" ";
cout<< i->second << endl;
}
return 0;
}
此代码仅在地图中添加 1 个元素,这是最近添加的元素。
我编辑了代码以使用 unordered_map,但仍然是同样的问题。
我进一步尝试打印地图的 size() 。在这两种情况下,地图 m1 的大小都显示为 1。
Miles Budnek 已经说明了您的问题。
如果您查看函数的文档 (http://www.cplusplus.com/reference/cstdlib/mbstowcs/),您会发现第三个参数并不期望转换为 wchar_t 的字节数,而是最大值您指向的缓冲区可以容纳的字符数。
它会在找到 \0 后停止(这恰好是 strlen 也在寻找的)。
因此,只需将您的第一个 mbstowcs 调用的第三个参数替换为 260(或 sizeof(test1)/sizeof(wchar_t)
,您就可以很好地解决这个问题 'a'。
如前所述,读取文件时没有 'escape parameters'。
这些仅存在于源代码中,表示您无法键入的 ASCII 代码。 (https://www.asciitable.com/)
\n 例如表示 'new line' 0x0A 的代码。
所以转义文件中的反斜杠是不必要的,可以跳过。
如果您知道您的输入文件将包含 'double backslashes' 并且需要 'unescape' 它们,您可以查看 std::string 函数 'find' 和 'replace'.
找到"\\"
(连续两个反斜杠)并替换为"\"
。
针对您更新后的问题(这基本上是另一个问题)的回应:
问题是您为地图选择的键。
每张地图,无论是否无序,都需要唯一的密钥,并且在您的场景中,您一直使用相同的密钥。
LPCWSTR
扩展为 'Pointer to Wide Char String',因此虽然您可能认为您使用 'abc\def\ghi' 作为键,但实际上您使用的是 &gr[0],它在所有迭代中保持不变.
作为一个额外的结果,一旦程序离开 gr
的范围,它的内容就变得无效并且访问映射(它维护指针但不维护内容),将访问容易崩溃的释放内存你的程序。
虽然这样的解决方案很简单:您需要使用内容作为键,而不是指针,例如使用像 std::wstring
.
这样的容器对象
我正在尝试使用 C++ 从文本文件中读取数据并将每行的字符串存储到 wchar_t [] 或 LPCWSTR 中。 (这 2 种数据类型是我正在处理的应用程序的约束。这就是为什么我必须将数据存储在这些数据类型中的原因)
.txt文件中的数据格式,例如:
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
我正在尝试逐行读取数据并将每一行保存为映射的键值对,其中键是LPCWSTR类型或wchar_t[]类型&值是int类型 提取 int 没有问题,但问题出在读取字符串
这是我的代码:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
using namespace std;
int main()
{
wchar_t test1[260];
const char* s = "Hello\ABC\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
wcout<<gr<<L" ";
cout<<percentage<<endl;
}
ifs.close();
}
return 0;
}
但是,它给出了以下输出:
Hello\ABC\DEFa
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
我不明白为什么那个小'a'突然出现在输出的第一行
我希望代码自动处理那些双斜杠,即我希望输出为:
Hello\ABC\DEF abc\def\ghi 10 jkl\mnopq\rstq 20 aqq\sdsds\qc 30
如果我可以在 .txt 文件中写入不带双斜杠的条目,并且它们会在不检查任何转义序列的情况下自动处理,那就更好了。但是,由于第 1 点中的问题。 1) 上面有,所以我不确定是否可能
即使在 while 循环的第一行添加
cout<<gr_temp<<endl;
,即使这样也会输出带有双反斜杠的字符串。
我错过了什么或做错了什么?
更新:
此外,当我在每个 while 循环末尾使用语句 m1[gr] = percentage;
将这些键值对添加到 std::map<LPCWSTR,int> m1
时,然后使用 print 语句,它只显示一个元素在地图上。
我的更新代码是:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
#include<map>
using namespace std;
std::unordered_map<LPCWSTR, int> m1;
int main()
{
wchar_t test1[260];
const char* s = "Hello\ABC\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
m1[gr] = percentage;
}
ifs.close();
}
for (auto i = m1.begin(); i != m1.end(); i++) {
wcout<< i->first << L" ";
cout<< i->second << endl;
}
return 0;
}
此代码仅在地图中添加 1 个元素,这是最近添加的元素。
我编辑了代码以使用 unordered_map,但仍然是同样的问题。
我进一步尝试打印地图的 size() 。在这两种情况下,地图 m1 的大小都显示为 1。
Miles Budnek 已经说明了您的问题。
如果您查看函数的文档 (http://www.cplusplus.com/reference/cstdlib/mbstowcs/),您会发现第三个参数并不期望转换为 wchar_t 的字节数,而是最大值您指向的缓冲区可以容纳的字符数。
它会在找到 \0 后停止(这恰好是 strlen 也在寻找的)。
因此,只需将您的第一个 mbstowcs 调用的第三个参数替换为 260(或 sizeof(test1)/sizeof(wchar_t)
,您就可以很好地解决这个问题 'a'。
如前所述,读取文件时没有 'escape parameters'。 这些仅存在于源代码中,表示您无法键入的 ASCII 代码。 (https://www.asciitable.com/)
\n 例如表示 'new line' 0x0A 的代码。
所以转义文件中的反斜杠是不必要的,可以跳过。
如果您知道您的输入文件将包含 'double backslashes' 并且需要 'unescape' 它们,您可以查看 std::string 函数 'find' 和 'replace'.
找到"\\"
(连续两个反斜杠)并替换为"\"
。
针对您更新后的问题(这基本上是另一个问题)的回应: 问题是您为地图选择的键。 每张地图,无论是否无序,都需要唯一的密钥,并且在您的场景中,您一直使用相同的密钥。
LPCWSTR
扩展为 'Pointer to Wide Char String',因此虽然您可能认为您使用 'abc\def\ghi' 作为键,但实际上您使用的是 &gr[0],它在所有迭代中保持不变.
作为一个额外的结果,一旦程序离开 gr
的范围,它的内容就变得无效并且访问映射(它维护指针但不维护内容),将访问容易崩溃的释放内存你的程序。
虽然这样的解决方案很简单:您需要使用内容作为键,而不是指针,例如使用像 std::wstring
.