C++ 减少特殊字符,例如 ü

问题描述 投票:0回答:4

我在使用 C++ 中的 tolower() 函数将字符串转换为小写时遇到问题。对于普通字符串,它可以按预期工作,但是特殊字符无法成功转换。

我如何使用我的功能:

string NotLowerCase = "Grüßen";
string LowerCase = "";
for (unsigned int i = 0; i < NotLowerCase.length(); i++) {
    LowerCase += tolower(NotLowerCase[i]);
    }

例如:

  1. 测试 -> 测试
  2. TeST2 -> 测试2
  3. Grüßen -> gr??????en
  4. (§) -> ()

3 和 4 没有按预期工作,如您所见

如何解决这个问题?我必须保留特殊字符,但要保留小写。

c++ character-encoding htmlspecialchars
4个回答
7
投票

来自

tolower
的示例代码(如下)显示了如何解决此问题;您必须使用默认“C”语言环境之外的其他语言。

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xb4'; // the character Ž in ISO-8859-15
                              // but ´ (acute accent) in ISO-8859-1 

    std::setlocale(LC_ALL, "en_US.iso88591");
    std::cout << std::hex << std::showbase;
    std::cout << "in iso8859-1, tolower('0xb4') gives "
              << std::tolower(c) << '\n';
    std::setlocale(LC_ALL, "en_US.iso885915");
    std::cout << "in iso8859-15, tolower('0xb4') gives "
              << std::tolower(c) << '\n';
}

您还可以将

std::string
更改为
std::wstring
,这是许多 C++ 实现上的 Unicode。

wstring NotLowerCase = L"Grüßen";
wstring LowerCase;
for (auto&& ch : NotLowerCase) {
    LowerCase += towlower(ch);
    }

Microsoft 的指导是“将字符串标准化为大写”,因此您可以使用

toupper
towupper
来代替。

请记住,逐个字符的转换可能不适用于某些语言。例如,使用德国所说的德语,将 Grüßen 全部大写,就会变成 GRÜESSEN(尽管现在有一个大写的 )。还有许多其他“问题”,例如组合字符;如果您正在使用字符串进行真正的“生产”工作,您确实需要一种完全不同的方法。

最后,C++ 对管理区域设置有更复杂的支持,请参阅

<locale>

 了解详细信息。
    


3
投票
我认为最便携的方法是使用

用户选择的区域设置,这是通过将区域设置设置为""

(空字符串)来实现的。

std::locale::global(std::locale(""));

这会将语言环境设置为程序运行时所使用的区域设置,并影响在多字节和宽字符串字符之间进行转换的标准字符转换例程(

std::mbsrtowcs & std::wcsrtombs)。

然后,您可以使用这些函数将系统/用户选择的多字节字符(例如

UTF-8

)转换为系统标准宽字符代码,这些代码可用于一次操作一个字符的函数(例如
std::tolower
) .

这很重要,因为像

UTF-8

这样的多字节字符集无法使用像
std::tolower()
这样的单字符操作进行转换。

将宽字符串版本转换为大写/小写后,可以将其转换回系统/用户多字节字符集以打印到控制台。

// Convert from multi-byte codes to wide string codes std::wstring mb_to_ws(std::string const& mb) { std::wstring ws; std::mbstate_t ps{}; char const* src = mb.data(); std::size_t len = 1 + mbsrtowcs(0, &src, 3, &ps); ws.resize(len); src = mb.data(); mbsrtowcs(&ws[0], &src, ws.size(), &ps); if(src) throw std::runtime_error("invalid multibyte character after: '" + std::string(mb.data(), src) + "'"); ws.pop_back(); return ws; } // Convert from wide string codes to multi-byte codes std::string ws_to_mb(std::wstring const& ws) { std::string mb; std::mbstate_t ps{}; wchar_t const* src = ws.data(); std::size_t len = 1 + wcsrtombs(0, &src, 0, &ps); mb.resize(len); src = ws.data(); wcsrtombs(&mb[0], &src, mb.size(), &ps); if(src) throw std::runtime_error("invalid wide character"); mb.pop_back(); return mb; } int main() { // set locale to the one chosen by the user // (or the one set by the system default) std::locale::global(std::locale("")); try { string NotLowerCase = "Grüßen"; std::cout << NotLowerCase << '\n'; // convert system/user multibyte character codes // to wide string versions std::wstring ws1 = mb_to_ws(NotLowerCase); std::wstring ws2; for(unsigned int i = 0; i < ws1.length(); i++) { // use the system/user locale ws2 += std::tolower(ws1[i], std::locale("")); } // convert wide string character codes back // to system/user multibyte versions string LowerCase = ws_to_mb(ws2); std::cout << LowerCase << '\n'; } catch(std::exception const& e) { std::cerr << e.what() << '\n'; return EXIT_FAILURE; } catch(...) { std::cerr << "Unknown exception." << '\n'; return EXIT_FAILURE; } return EXIT_SUCCESS; }

代码未经严格测试


0
投票
我不喜欢更改 std::locale,因此我编写了一个小映射函数,将 Unicode 表的(最相关的?)字符转换为小写。也许它对你来说很方便。

wchar_t unicode_tolower(wchar_t c) { #define LWR_OFFSET(from, to, by){if(c>=(from) && c<=(to)){return c+(by);}} #define LWR_NEXT(from, to){const int odd = (from) & 0x0001; if(c>=(from) && c<=(to) && ((c&0x0001) == odd)) {return ++c;}} LWR_OFFSET(L'A', L'Z', 0x20) LWR_OFFSET(0x00c0, 0x00d6, 0x20) // A with grave ... O with diaeresis // 0x00d7=multiplication LWR_OFFSET(0x00d8, 0x00de, 0x20) // O with stroke ...Thorn LWR_NEXT(0x0100, 0x017e) // A with macron ... Z with caron LWR_NEXT(0x0370, 0x0376) // greek LWR_OFFSET(0x0391, 0x03ab, 0x20) // greek if (c==0x03f7) {return ++c;} if (c==0x03fa) {return ++c;} LWR_OFFSET(0x0400, 0x040f, 0x50) // Cyrillic - this range is strange LWR_OFFSET(0x0410, 0x042f, 0x20) // Cyrillic LWR_NEXT(0x0460, 0x04bf) LWR_NEXT(0x04c1, 0x04ce) LWR_NEXT(0x04d0, 0x052f) LWR_OFFSET(0x0531, 0x0556, 0x30) // Armenian return c; #undef LWR_OFFSET #undef LWR_NEXT }
    

-6
投票
使用ASCII

string NotLowerCase = "Grüßen"; string LowerCase = ""; for (unsigned int i = 0; i < NotLowerCase.length(); i++) { if(NotLowerCase[i]<65||NotLowerCase[i]>122) { LowerCase+='?'; } else LowerCase += tolower(NotLowerCase[i]); }
    
© www.soinside.com 2019 - 2024. All rights reserved.