提问人:Konrad 提问时间:11/24/2008 最后编辑:Peter MortensenKonrad 更新时间:6/23/2023 访问量:1311933
如何将 std::string 的实例转换为小写
How to convert an instance of std::string to lower case
问:
我想将 a 转换为小写。我知道这个功能。但是,过去我遇到过这个函数的问题,无论如何它都不是理想的,因为将它与 a 一起使用需要遍历每个字符。std::string
tolower()
std::string
有没有一种 100% 有效的替代方案?
答:
#include <boost/algorithm/string.hpp>
std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str
#include <boost/algorithm/string.hpp>
const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);
评论
改编自不那么常见的问题:
#include <algorithm>
#include <cctype>
#include <string>
std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
[](unsigned char c){ return std::tolower(c); });
如果不遍历每个角色,你真的不会逃脱。否则,无法知道字符是小写还是大写。
如果你真的讨厌 tolower(),
这里有一个专门的仅限 ASCII 的替代方案,我不建议你使用:
char asciitolower(char in) {
if (in <= 'Z' && in >= 'A')
return in - ('Z' - 'z');
return in;
}
std::transform(data.begin(), data.end(), data.begin(), asciitolower);
请注意,它只能执行每个单字节字符的替换,这不适合许多脚本,尤其是在使用 UTF-8 等多字节编码时。tolower()
评论
char
::tolower(int)
如果字符串包含 ASCII 范围之外的 UTF-8 字符,则 boost::algorithm::to_lower 将不会转换这些字符。当涉及 UTF-8 时,最好使用 boost::locale::to_lower。查看 http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/conversions.html
评论
这是 Stefan Mai 回应的后续:如果您想将转换结果放在另一个字符串中,您需要在调用 .由于 STL 将转换后的字符存储在目标迭代器中(在循环的每次迭代中递增),因此目标字符串不会自动调整大小,并且您有内存踩踏的风险。std::transform
#include <string>
#include <algorithm>
#include <iostream>
int main (int argc, char* argv[])
{
std::string sourceString = "Abc";
std::string destinationString;
// Allocate the destination space
destinationString.resize(sourceString.size());
// Convert the source string to lower case
// storing the result in destination string
std::transform(sourceString.begin(),
sourceString.end(),
destinationString.begin(),
::tolower);
// Output the result of the conversion
std::cout << sourceString
<< " -> "
<< destinationString
<< std::endl;
}
评论
Boost 的替代品是 POCO (pocoproject.org)。
POCO 提供两种变体:
- 第一个变体在不更改原始字符串的情况下进行复制。
- 第二个变体更改了原有的字符串。
“就地”版本的名称中始终包含“InPlace”。
两个版本如下所示:
#include "Poco/String.h"
using namespace Poco;
std::string hello("Stack Overflow!");
// Copies "STACK OVERFLOW!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));
// Changes newString in-place to read "stack overflow!"
toLowerInPlace(newString);
使用基于范围的 for 循环 C++11 更简单的代码是:
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::tolower
int main ()
{
std::locale loc;
std::string str="Test String.\n";
for(auto elem : str)
std::cout << std::tolower(elem,loc);
}
评论
有一种方法可以将大写转换为小写,而无需进行 if 测试,而且非常简单。isupper() 函数/宏对 clocale.h 的使用应该可以解决与您的位置相关的问题,但如果没有,您可以随时根据自己的喜好调整 UtoL[]。
鉴于 C 的字符实际上只是 8 位整数(暂时忽略宽字符集),您可以创建一个 256 字节的数组来保存一组替代字符,并在转换函数中使用字符串中的字符作为下标进入转换数组。
但是,不要使用 1 对 1 映射,而是为大写数组成员提供小写字符的 BYTE int 值。您可能会发现 islower() 和 isupper() 在这里很有用。
代码如下所示...
#include <clocale>
static char UtoL[256];
// ----------------------------------------------------------------------------
void InitUtoLMap() {
for (int i = 0; i < sizeof(UtoL); i++) {
if (isupper(i)) {
UtoL[i] = (char)(i + 32);
} else {
UtoL[i] = i;
}
}
}
// ----------------------------------------------------------------------------
char *LowerStr(char *szMyStr) {
char *p = szMyStr;
// do conversion in-place so as not to require a destination buffer
while (*p) { // szMyStr must be null-terminated
*p = UtoL[*p];
p++;
}
return szMyStr;
}
// ----------------------------------------------------------------------------
int main() {
time_t start;
char *Lowered, Upper[128];
InitUtoLMap();
strcpy(Upper, "Every GOOD boy does FINE!");
Lowered = LowerStr(Upper);
return 0;
}
同时,这种方法将允许您重新映射要更改的任何其他字符。
这种方法在现代处理器上运行时具有一个巨大的优势,无需进行分支预测,因为没有包含分支的 if 测试。这样可以节省 CPU 对其他循环的分支预测逻辑,并倾向于防止管道停顿。
这里的一些人可能会将这种方法与用于将 EBCDIC 转换为 ASCII 的方法相同。
评论
TL的;博士
使用 ICU 库。如果你不这样做,你的转换例程将在你甚至可能不知道存在的案例上悄无声息地中断。
首先,你必须回答一个问题:你的编码是什么?是ISO-8859-1吗?或者也许是 ISO-8859-8?还是 Windows 代码页 1252?你用来将大写字母转换为小写字母的任何东西都知道吗?(或者它是否为角色惨遭失败?std::string
0x7f
如果你使用 UTF-8(8 位编码中唯一理智的选择)作为容器,如果你相信你仍然在控制事物,你就已经在欺骗自己了。您将多字节字符序列存储在不知道多字节概念的容器中,并且您可以对其执行的大多数操作也无法执行!即使是像这样简单的东西也可能导致无效的(子)字符串,因为您在多字节序列的中间进行拆分。std::string
.substr()
一旦你尝试类似的东西,或者任何编码,你就有麻烦了。因为 1),该标准一次只能对一个字符进行操作,因此它根本无法转换为正确的字符。2)标准一次只对一个字符进行操作,因此它无法决定是在单词的中间(哪里是正确的),还是在结尾()。另一个例子是 ,它应该根据语言环境产生不同的结果 - 几乎在所有你期望的地方,但在土耳其(拉丁文小写字母 DOTLESS I)是正确的答案(同样,在 UTF-8 编码中,它不止一个字节)。std::toupper( 'ß' )
std::tolower( 'Σ' )
ß
SS
Σ
σ
ς
std::tolower( 'I' )
i
ı
因此,任何一次对一个字符起作用的大小写转换,或者更糟糕的是,一次对一个字节起作用,都会被设计破坏。这包括目前存在的所有变体。std::
还有一点是,标准库,就它能够做什么而言,取决于运行软件的机器上支持哪些语言环境......如果您的目标区域设置在客户端计算机上不受支持,您会怎么做?
因此,您真正要寻找的是一个能够正确处理所有这些的字符串类,而不是任何 std::basic_string<>
变体。
(C++11 注:并且更好,但仍然不完美。C++20 带来了 ,但所有这些所做的只是指定编码。在许多其他方面,他们仍然对Unicode机制一无所知,例如规范化,排序规则等。std::u16string
std::u32string
std::u8string
虽然 Boost 看起来不错,但 API 方面,Boost.Locale 基本上是 ICU 的包装器。如果Boost 是在 ICU 支持下编译的......如果不是,则 Boost.Locale 仅限于为标准库编译的区域设置支持。
相信我,让 Boost 与 ICU 一起编译有时真的很痛苦。(Windows 没有包含 ICU 的预编译二进制文件,因此您必须将它们与应用程序一起提供,这会打开一个全新的蠕虫罐头......
因此,就我个人而言,我建议直接从马的嘴里获得完整的Unicode支持,并直接使用ICU库:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "\n";
std::cout << someUString.toUpper( "el_GR" ) << "\n";
return 0;
}
编译(在此示例中使用 G++):
g++ -Wall example.cpp -licuuc -licuio
这给出了:
ὀδυσσεύς
请注意,单词中间的 Σ<->σ 转换,以及单词末尾的 Σ<->ς 转换。任何基于解决方案都无法为您提供这种服务。<algorithm>
评论
在 Microsoft 平台上,可以使用以下函数系列: http://msdn.microsoft.com/en-us/library/hkxwh33z.aspxstrlwr
// crt_strlwr.c
// compile with: /W3
// This program uses _strlwr and _strupr to create
// uppercase and lowercase copies of a mixed-case string.
#include <string.h>
#include <stdio.h>
int main( void )
{
char string[100] = "The String to End All Strings!";
char * copy1 = _strdup( string ); // make two copies
char * copy2 = _strdup( string );
_strlwr( copy1 ); // C4996
_strupr( copy2 ); // C4996
printf( "Mixed: %s\n", string );
printf( "Lower: %s\n", copy1 );
printf( "Upper: %s\n", copy2 );
free( copy1 );
free( copy2 );
}
将字符串转换为 loweercase 而不用担心 std 命名空间的最简单方法如下
1:带/不带空格的字符串
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
getline(cin,str);
//------------function to convert string into lowercase---------------
transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
cout<<str;
return 0;
}
2:不带空格的字符串
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
cin>>str;
//------------function to convert string into lowercase---------------
transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
cout<<str;
return 0;
}
评论
std::tolower
char
unsigned char
str
str
std::ctype::tolower()
来自标准 C++ 本地化库将为您正确执行此操作。下面是从 tolower 参考页面中提取的示例
#include <locale>
#include <iostream>
int main () {
std::locale::global(std::locale("en_US.utf8"));
std::wcout.imbue(std::locale());
std::wcout << "In US English UTF-8 locale:\n";
auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
std::wstring str = L"HELLo, wORLD!";
std::wcout << "Lowercase form of the string '" << str << "' is ";
f.tolower(&str[0], &str[0] + str.size());
std::wcout << "'" << str << "'\n";
}
评论
const
f.tolower()
transform()
std::bind1st( std::mem_fun() )
tolower
locale
use_facet
boost::iequals
use_facet
如果您想要一些简单的东西,这里有一个宏技术:
#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower)
#define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper)
#define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(), ::toupper); std::transform (x.begin()+1, x.end(), x.begin()+1,::tolower)
但是,请注意,@AndreasSpindler对这个答案的评论仍然是一个重要的考虑因素,但是,如果您正在研究的不仅仅是 ASCII 字符。
评论
void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
x
另一种使用基于范围的for循环的方法,带有参考变量
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
cout<<test<<endl;
评论
// tolower example (C++)
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::tolower
int main ()
{
std::locale loc;
std::string str="Test String.\n";
for (std::string::size_type i=0; i<str.length(); ++i)
std::cout << std::tolower(str[i],loc);
return 0;
}
欲了解更多信息,请访问:http://www.cplusplus.com/reference/locale/tolower/
代码片段
#include<bits/stdc++.h>
using namespace std;
int main ()
{
ios::sync_with_stdio(false);
string str="String Convert\n";
for(int i=0; i<str.size(); i++)
{
str[i] = tolower(str[i]);
}
cout<<str<<endl;
return 0;
}
从 fplus 库使用。fplus::to_lower_case()
在 fplus API 搜索中搜索to_lower_case
例:
fplus::to_lower_case(std::string("ABC")) == std::string("abc");
此解决方案工作原理的说明:
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
解释:
for(auto& c : test)
是一个基于范围的 for 循环,range_declaration
range_expression
loop_statement
:for (
:
)
range_declaration
:
这里的自动说明符用于自动类型推导。因此,该类型是从变量初始值设定项中扣除的。auto& c
range_expression
:
本例中的范围是字符串的字符。test
test
字符串的字符可作为 for 循环标识符内的引用。test
c
评论
std::transform
有没有一种 100% 有效的替代方案?
不
在选择小写方法之前,您需要问自己几个问题。
- 字符串是如何编码的?纯 ASCII?UTF-8?某种形式的扩展 ASCII 传统编码?
- 小写是什么意思?案例映射规则因语言而异!您是否想要针对用户区域设置进行本地化的内容?您是否希望在运行软件的所有系统上都具有一致的行为?您只想小写 ASCII 字符并传递其他所有内容吗?
- 有哪些库可用?
一旦你有了这些问题的答案,你就可以开始寻找适合你需求的解决方案。没有一种尺寸适合任何地方的每个人!
C++ 没有为 实现 或 方法,但它可用于 。人们可以很容易地读取字符串的每个字符,将其转换为所需的大小写,然后将其放回字符串中。
不使用任何第三方库的示例代码:tolower
toupper
std::string
char
#include<iostream>
int main(){
std::string str = std::string("How ARe You");
for(char &ch : str){
ch = std::tolower(ch);
}
std::cout<<str<<std::endl;
return 0;
}
对于字符串上基于字符的操作:对于字符串中的每个字符
由于没有一个答案提到即将到来的范围库,该库自 C++20 以来在标准库中可用,目前在 GitHub 上单独提供,我想添加一种使用它执行此转换的方法。range-v3
要就地修改字符串,请执行以下操作:
str |= action::transform([](unsigned char c){ return std::tolower(c); });
要生成新字符串,请执行以下操作:
auto new_string = original_string
| view::transform([](unsigned char c){ return std::tolower(c); });
(不要忘记和所需的 Ranges 标头。#include <cctype>
注意:使用 of 作为 lambda 的参数是受 cpppreference 的启发,它指出:unsigned char
与 的所有其他函数一样,如果参数的值既不能表示为也不能等于 ,则 的行为是未定义的。为了安全地使用普通 s(或 s)的这些函数,应首先将参数转换为:
<cctype>
std::tolower
unsigned char
EOF
char
signed char
unsigned char
char my_tolower(char ch) { return static_cast<char>(std::tolower(static_cast<unsigned char>(ch))); }
同样,当迭代器的值类型为 或 时,它们不应直接与标准算法一起使用。相反,请将该值转换为 first:
char
signed char
unsigned char
std::string str_tolower(std::string s) { std::transform(s.begin(), s.end(), s.begin(), // static_cast<int(*)(int)>(std::tolower) // wrong // [](int c){ return std::tolower(c); } // wrong // [](char c){ return std::tolower(c); } // wrong [](unsigned char c){ return std::tolower(c); } // correct ); return s; }
我自己的模板功能,可以执行大写/小写。
#include <string>
#include <algorithm>
//
// Lowercases string
//
template <typename T>
std::basic_string<T> lowercase(const std::basic_string<T>& s)
{
std::basic_string<T> s2 = s;
std::transform(s2.begin(), s2.end(), s2.begin(),
[](const T v){ return static_cast<T>(std::tolower(v)); });
return s2;
}
//
// Uppercases string
//
template <typename T>
std::basic_string<T> uppercase(const std::basic_string<T>& s)
{
std::basic_string<T> s2 = s;
std::transform(s2.begin(), s2.end(), s2.begin(),
[](const T v){ return static_cast<T>(std::toupper(v)); });
return s2;
}
评论
towlower
试试这个函数:)
string toLowerCase(string str) {
int str_len = str.length();
string final_str = "";
for(int i=0; i<str_len; i++) {
char character = str[i];
if(character>=65 && character<=92) {
final_str += (character+32);
} else {
final_str += character;
}
}
return final_str;
}
评论
我写了这个简单的辅助函数:
#include <locale> // tolower
string to_lower(string s) {
for(char &c : s)
c = tolower(c);
return s;
}
用法:
string s = "TEST";
cout << to_lower("HELLO WORLD"); // output: "hello word"
cout << to_lower(s); // won't change the original variable.
为 ASCII 字符串to_lower添加一些可选库,这两个库都是生产级的,并且进行了微优化,预计会比这里的现有答案更快(TODO:添加基准测试结果)。
Facebook的愚蠢:
void toLowerAscii(char* str, size_t length)
谷歌的绳降:
void AsciiStrToLower(std::string* s);
我写了一个适用于任何字符串的模板化版本:
#include <type_traits> // std::decay
#include <ctype.h> // std::toupper & std::tolower
template <class T = void> struct farg_t { using type = T; };
template <template<typename ...> class T1,
class T2> struct farg_t <T1<T2>> { using type = T2*; };
//---------------
template<class T, class T2 =
typename std::decay< typename farg_t<T>::type >::type>
void ToUpper(T& str) { T2 t = &str[0];
for (; *t; ++t) *t = std::toupper(*t); }
template<class T, class T2 = typename std::decay< typename
farg_t<T>::type >::type>
void Tolower(T& str) { T2 t = &str[0];
for (; *t; ++t) *t = std::tolower(*t); }
使用 gcc 编译器测试:
#include <iostream>
#include "upove_code.h"
int main()
{
std::string str1 = "hEllo ";
char str2 [] = "wOrld";
ToUpper(str1);
ToUpper(str2);
std::cout << str1 << str2 << '\n';
Tolower(str1);
Tolower(str2);
std::cout << str1 << str2 << '\n';
return 0;
}
输出:
>HELLO WORLD
>
>hello world
看看优秀的 c++17 cpp-unicodelib (GitHub)。它是单文件和仅标头。
#include <exception>
#include <iostream>
#include <codecvt>
// cpp-unicodelib, downloaded from GitHub
#include "unicodelib.h"
#include "unicodelib_encodings.h"
using namespace std;
using namespace unicode;
// converter that allows displaying a Unicode32 string
wstring_convert<codecvt_utf8<char32_t>, char32_t> converter;
std::u32string in = U"Je suis là!";
cout << converter.to_bytes(in) << endl;
std::u32string lc = to_lowercase(in);
cout << converter.to_bytes(lc) << endl;
输出
Je suis là!
je suis là!
评论
使用此代码更改 C++ 中字符串的大小写。
#include<bits/stdc++.h>
using namespace std;
int main(){
string a = "sssAAAAAAaaaaDas";
transform(a.begin(),a.end(),a.begin(),::tolower);
cout<<a;
}
评论
#include <bits/stdc++.h>
谷歌的图书馆有absl
absl::AsciiStrToLower
/ absl::AsciiStrToUpper
由于您使用的是 std::string,因此您使用的是 c++。如果使用 c++11 或更高版本,则不需要任何花哨的东西。如果为 ,则:words
vector<string>
for (auto & str : words) {
for(auto & ch : str)
ch = tolower(ch);
}
没有奇怪的例外。可能想使用w_char,但除此之外,这应该可以完成所有工作。
从另一个角度来看,有一个非常常见的用例,即对 Unicode 字符串执行区域设置中性大小写折叠。对于这种情况,当您意识到可折叠字符集是有限的且相对较小(< 2000 个 Unicode 码位)时,可以获得良好的大小写折叠性能。它恰好与生成的完美哈希(保证零冲突)配合得很好,可用于将每个输入字符转换为其小写等效字符。
使用 UTF-8 时,您必须注意多字节字符并相应地进行迭代。但是,UTF-8 具有相当简单的编码规则,可以使此操作高效。
有关更多详细信息,包括指向Unicode标准相关部分的链接和完美的哈希生成器,请参阅我在这里对如何在C++中实现与Unicode无关的大小写不区分比较的问题的回答。
评论
tolower()
tolower