首先,我写了一个模板日志函数如下:
void Utils::_logMap(std::map<K, V> map) {
cout << "===================[map]=====================\n";
for(auto it: map) {
auto key = it.first;
auto val = it.second;
cout << key << " = " << val << endl;
}
// testing code
cout << "\n>>> for testing: \n";
cout << map.at("S_WARNING_UNABLE_TO_PUT_INTO_WEREHOUSE") << endl;
cout << map.at("S_HELLO") << endl;
cout << map.at("S_TEST") << endl;
}
然后我创建一个std :: map对象,并从文件中读取文本内容(使用UTF-8编码的本地化语言txt文件)。
static std::map<string, string> localizedStrings;
然后我打印出它的所有键值。
Utils::_logMap(localizedStrings);
结果显示:
===================[map]=====================
S_HELLO = hello123
S_WARNING_UNABLE_TO_PUT_INTO_WEREHOUSE = teest1312
S_TEST = Test777
>>> for testing:
teest1312
hello123
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: map::at: key not found
最后一行out_of_range异常是由此代码引起的:
cout << map.at("S_HELLO") << endl; // for testing, app will crash
但这怎么可能!!?!? map对象确实包含一个名为S_HELLO的键。当我尝试通过键入常量字符串值来访问密钥时,为什么应用程序会出现异常!?我不明白!
更新: 好吧,这是主要的阅读内容功能代码:
string Utils::getLocalizedString(const string key) {
LanguageType type = Application::getInstance()->getCurrentLanguage();
const char* code = Application::getInstance()->getCurrentLanguageCode();
cclog("language type: %d, code: %s", type, code);
const char * fileName;
switch (type) {
case LanguageType::ENGLISH:
fileName = "Localized_en.txt";
break;
case LanguageType::CHINESE:
fileName = "Localized_zh.txt";
break;
default:
fileName = "Localized_en.txt";
break;
}
if (localizedStrings.empty()) {
// Initialize variables needed
ssize_t fileSize = 0;
unsigned char * fileContents = NULL;
string line, fullPath, contents;
// Get absolute path of file
fullPath = FileUtils::getInstance()->fullPathForFilename( fileName );
cout << "fullPath: " << fullPath << endl;
// Get data of file
if( !fullPath.empty() ) {
fileContents = CCFileUtils::getInstance()->getFileData( fullPath.c_str( ) , "rb", &fileSize );
cout << "fileContents: " << fileContents << endl;
contents.assign(fileContents,fileContents+fileSize-1);
// Create a string stream so that we can use getline( ) on it
istringstream fileStringStream( contents );
// Get file contents line by line
while ( std::getline( fileStringStream, line ) )
{
//filter the valid string of one line
if (line.find("/*",0) == string::npos && line.find("//",0) == string::npos) {
std::string::size_type validPos= line.find('=',0);
if ( validPos != string::npos)
{
std::string keyStr = line.substr(0,validPos-1);
std::string subStr = line.substr(validPos+1,line.size()-1); // get valid string
//trim space
keyStr.erase(0, keyStr.find_first_not_of(" \t")); // remove head white-space
keyStr.erase(keyStr.find_last_not_of(" \t") + 1); // remove tail white-space
subStr.erase(0, subStr.find_first_not_of(" \t")); // remove head white-space
subStr.erase(subStr.find_last_not_of(" \t") + 1); // remove tail white-space
//trim \"
keyStr.erase(0, keyStr.find_first_not_of("\""));
keyStr.erase(keyStr.find_last_not_of("\"") + 1);
subStr.erase(0, subStr.find_first_not_of("\""));
//trim ; character and last \" character
subStr.erase(subStr.find_last_not_of(";") + 1);
subStr.erase(subStr.find_last_not_of("\"") + 1);
//replace line feed with \n
string::size_type pos(0);
string old_value("\\n");
if((pos=subStr.find(old_value))!=string::npos)
{
for(; pos!=string::npos; pos+=1)
{
if((pos=subStr.find(old_value,pos))!=string::npos)
{
subStr.erase(pos, 2);
subStr.insert(pos, 1, '\n');
}
else
break;
}
}
localizedStrings.insert(std::pair<std::string, std::string>(keyStr,subStr));
}
}
}
}
//must delete fileContents
if (fileContents!= NULL) {
delete [] fileContents;
fileContents = NULL;
}
}
cout << "key: " + key << endl;
logMap(localizedStrings);
if( localizedStrings.find(key) != localizedStrings.end() ) {
return localizedStrings.at(key);
}
cclog("return key instead");
return key;
}
已更新 天啊,我发现它似乎与文件中文本的位置相关。只有FIRST行文件中的键值才会导致问题。 但我还是不知道为什么........
这是本地化字符串文件的内容:
S_TEST = Test777
S_HELLO = hello123
S_WARNING_UNABLE_TO_PUT_INTO_WEREHOUSE = teest13124
见?如果我访问键S_HELLO和S_WARNINGxxx,它工作正常。但如果我访问密钥S_TEST,它将崩溃....
答案 0 :(得分:1)
如果只有文件中的第一个键出现此问题,那么您的文件开头很可能是BOM
(字节顺序标记)。这些是2个不可见的字节,许多Windows编辑器默认将这些字节插入UTF-8文件中。
使用Notepad ++删除BOM
打开文件。在Encoding
菜单中选择Encode in UTF-8 without BOM
。然后再次保存文件。
答案 1 :(得分:0)
嗯......这个崩溃问题似乎是由于从第一行的本地化txt文件中读取了某些不可见的字符。
所以我做了一个解决方案:只需在第一行插入注释文本,然后解决问题。它可能是文件是UTF-8格式,因此它在文件开头包含一些UTF-8格式标头,不应该读入字符串映射。
// !!LEAVE THE FIRST LINE EMTPY!!
S_TEST = Test777
S_HELLO = hello123
S_WARNING_UNABLE_TO_PUT_INTO_WEREHOUSE = Unable to put into werehouse
答案 2 :(得分:0)
map :: at和map :: []之间的区别在于它将检查该键是否存在于地图中。如果key不存在,则会抛出异常。 Operator []将在地图中添加新密钥。在您的情况下,地图不会崩溃但会抛出异常。将键添加到地图中或处理异常或使用operator []而不是at。