I want to convert a std::string
to lowercase. I am aware of the function tolower()
, however in the past I have had issues with this function and it
This could be another simple version to convert uppercase to lowercase and vice versa. I used VS2017 community version to compile this source code.
#include <iostream>
#include <string>
using namespace std;
int main()
{
std::string _input = "lowercasetouppercase";
#if 0
// My idea is to use the ascii value to convert
char upperA = 'A';
char lowerA = 'a';
cout << (int)upperA << endl; // ASCII value of 'A' -> 65
cout << (int)lowerA << endl; // ASCII value of 'a' -> 97
// 97-65 = 32; // Difference of ASCII value of upper and lower a
#endif // 0
cout << "Input String = " << _input.c_str() << endl;
for (int i = 0; i < _input.length(); ++i)
{
_input[i] -= 32; // To convert lower to upper
#if 0
_input[i] += 32; // To convert upper to lower
#endif // 0
}
cout << "Output String = " << _input.c_str() << endl;
return 0;
}
Note: if there are special characters then need to be handled using condition check.
std::ctype::tolower()
from the standard C++ Localization library will correctly do this for you. Here is an example extracted from the tolower reference page
#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";
}
Here's a macro technique if you want something simple:
#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)
However, note that @AndreasSpindler's comment on this answer still is an important consideration, however, if you're working on something that isn't just ASCII characters.
Since none of the answers mentioned the upcoming Ranges library, which is available in the standard library since C++20, and currently separately available on GitHub as range-v3
, I would like to add a way to perform this conversion using it.
To modify the string in-place:
str |= action::transform([](unsigned char c){ return std::tolower(c); });
To generate a new string:
auto new_string = original_string
| view::transform([](unsigned char c){ return std::tolower(c); });
(Don't forget to #include <cctype>
and the required Ranges headers.)
Note: the use of unsigned char
as the argument to the lambda is inspired by cppreference, which states:
Like all other functions from
<cctype>
, the behavior ofstd::tolower
is undefined if the argument's value is neither representable asunsigned char
nor equal toEOF
. To use these functions safely with plainchar
s (orsigned char
s), the argument should first be converted tounsigned char
:char my_tolower(char ch) { return static_cast<char>(std::tolower(static_cast<unsigned char>(ch))); }
Similarly, they should not be directly used with standard algorithms when the iterator's value type is
char
orsigned char
. Instead, convert the value tounsigned char
first: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; }
An alternative to Boost is POCO (pocoproject.org).
POCO provides two variants:
Both versions are demonstrated below:
#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);
Copy because it was disallowed to improve answer. Thanks SO
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
Explanation:
for(auto& c : test)
is a range-based for loop of the kind
for (
range_declaration
:
range_expression
)
loop_statement
:
range_declaration
: auto& c
Here the auto specifier is used for for automatic type deduction. So the type gets deducted from the variables initializer.
range_expression
: test
The range in this case are the characters of string test
.
The characters of the string test
are available as a reference inside the for loop through identifier c
.