Как преобразовать std :: string в нижний регистр?


777

Я хочу преобразовать std::stringв нижний регистр. Я знаю о функции tolower(), однако в прошлом у меня были проблемы с этой функцией, и в любом случае она вряд ли идеальна, так как использование с std::stringтребовало бы итерации по каждому символу.

Есть ли альтернатива, которая работает 100% времени?


34
Как еще вы могли бы преобразовать каждый элемент списка чего-либо во что-то еще, не просматривая список? Строка - это просто список символов. Если вам нужно применить какую-то функцию к каждому символу, вам придется перебирать строку. Обойти это невозможно.

14
Почему именно этот вопрос заслуживает рейтинга? У меня нет проблем с повторением моей строки, но я спрашиваю, есть ли другие функции, кроме tolower (), toupper () и т. Д.
Конрад,

3
Если у вас есть массив символов в стиле C, то, я думаю, вы сможете добавить ox20202020 в каждый блок из 4 символов (при условии, что они ВСЕ уже прописными), чтобы одновременно преобразовывать 4 символа в нижний регистр.

13
@Dan: Если они уже могут быть в нижнем регистре, но определенно AZ или az, вы можете ИЛИ с 0x20 вместо добавления. Одна из тех оптимистичных оптимизаций, которые, вероятно, глупы, которые почти никогда не стоят того ...
Стив Джессоп

4
Я не знаю, почему за него проголосовали ... конечно, это звучит немного странно (потому что вам нужно как-то перебирать каждый пункт), но это верный вопрос
Уорн

Ответы:


906

Адаптировано из не так часто задаваемых вопросов :

#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);

Имейте в виду, что tolower()можно выполнять замену только одного байта символа, что плохо подходит для многих сценариев, особенно при использовании многобайтовой кодировки, такой как UTF-8.


25
(Может быть, старые, рассматриваемые алгоритмы мало изменились) @Stefan Mai: Какого рода «издержки» возникают при вызове алгоритмов STL? Функции довольно просты (то есть просты для циклов) и часто встроены, поскольку у вас редко бывает много вызовов одной и той же функции с одинаковыми параметрами шаблона в одном и том же модуле компиляции.
11.11.11

257
Каждый раз, когда вы предполагаете, что символы ASCII, Бог убивает котенка. :(
Брайан Гордон

13
Ваш первый пример потенциально имеет неопределенное поведение (переход charк ::tolower(int).). Вы должны убедиться, что не передаете отрицательное значение.
Juanchopanza

37
-1 это использование ::tolowerможет привести к сбою, это UB для ввода не-ASCII.
ура и hth. - Альф

7
Символ :: необходим перед полнотой, чтобы указать, что он находится во внешнем пространстве имен. Если вы используете этот код в другом пространстве имен, может существовать другое (возможно, не связанное) определение tolower, которое в конечном итоге будет предпочтительно выбрано без ::.
Чарльз Офрия

320

Boost предоставляет строковый алгоритм для этого :

#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);

2
Я предполагаю, что это не имеет те же проблемы, что и Tolower с входом ASCII?
Пол

19
Не для ASCII-7.
DevSolar

1
Есть ли не-версия этого варианта?
Рэй

5
@ Луч, да,to_lower_copy
smac89

234

ТЛ; др

Используйте библиотеку ICU . Если вы этого не сделаете, ваша процедура преобразования будет молча нарушать случаи, о которых вы, вероятно, даже не подозреваете.


Сначала вы должны ответить на вопрос: какова ваша кодировкаstd::string ? Это ISO-8859-1? Или, возможно, ISO-8859-8? Или кодовая страница Windows 1252? Знает ли это то, что вы используете для преобразования прописных букв в строчные? (Или это с треском проваливается для персонажей более 0x7f?)

Если вы используете UTF-8 (единственный разумный выбор среди 8-битных кодировок) в std::stringкачестве контейнера, вы уже обманываете себя, полагая, что вы все еще контролируете вещи, потому что вы храните многобайтовую последовательность символов в контейнере который не знает о многобайтовой концепции. Даже .substr()такая простая вещь, как бомба замедленного действия. (Поскольку разбиение многобайтовой последовательности приведет к недопустимой (под) строке.)

И как только вы попробуете что-то подобное std::toupper( 'ß' ), в любой кодировке, у вас будут большие проблемы. (Потому что просто невозможно сделать это «правильно» со стандартной библиотекой, которая может доставить только один символ результата, а не "SS"необходимый здесь.) [1] Другой пример std::tolower( 'I' ), который должен давать разные результаты в зависимости от локали . В Германии 'i'было бы правильно; в индейке,'ı' (LATIN SMALL LETTER I DOTLESS I) является ожидаемым результатом (который, опять же, составляет более одного байта в кодировке UTF-8). Еще один пример - греческая сигма , прописные '∑', строчные 'σ'... за исключением конца слова, где оно находится 'ς'.

Так, любое преобразование, которое работает с символом за раз или, что еще хуже, с байтом за раз, нарушается по замыслу.

Тогда есть смысл, что стандартная библиотека, для чего она это способен делать, в зависимости от того , локали поддерживается на машине ваше программное обеспечение работает на ... и что делать , если это не так ?

Так что вы действительно ищете строковый класс, который способен справиться со всем этим правильно, и это не какой-либо из std::basic_string<>вариантов .

(Примечание C ++ 11: std::u16string и std::u32stringэто лучше ., Но все еще не совершенны C ++ 20 принес std::u8string, но все это сделать , это указать кодировку во многих других отношениях они все еще остаются в неведении о механике Unicode, как нормализация, обобщению, ... .)

Хотя Boost выглядит неплохо, с точки зрения API, Boost.Locale по сути является оболочкой для ICU .Если Boost скомпилирован с поддержкой ICU ... если нет, Boost.Locale ограничен поддержкой локали, скомпилированной для стандартной библиотеки.

И поверьте мне, заставить Boost компилироваться с ICU иногда бывает очень больно. (Для Windows нет предварительно скомпилированных двоичных файлов, так что вам придется поставлять их вместе с вашим приложением, и это открывает новую банку с червями ...)

Поэтому лично я бы порекомендовал получить полную поддержку 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>решение не может дать вам это.


[1] В 2017 году Совет по немецкой орфографии постановил, что "ẞ" U + 1E9E LATIN CAPITAL LAPTER SHARP S может быть официально использован, как вариант, помимо традиционной конверсии "SS", чтобы избежать двусмысленности, например, в паспортах (где имена пишутся с большой буквы) ). Мой прекрасный пример, устарел по решению комитета ...


19
Это правильный ответ в общем случае. Стандарт не дает ничего для обработки чего-либо, кроме "ASCII", кроме лжи и обмана. Это заставляет вас думать, что вы можете иметь дело с UTF-16, но не можете. Как говорится в этом ответе, вы не можете получить правильную длину символа (не длину байта) строки UTF-16, не выполняя собственную обработку Unicode. Если вам приходится иметь дело с реальным текстом, используйте ICU. Спасибо @DevSolar
ограниченное искупление

Доступен ли ICU по умолчанию в Ubuntu / Windows или его нужно устанавливать отдельно? А как насчет этого ответа: stackoverflow.com/a/35075839/207661 ?
Шиталь Шах

1
Эй, смотри, реальный ответ! Спасибо, что указал мне правильное прямое направление, DevSolar.
Дэн Бешард

2
@DevSolar Согласен! Понятие длины довольно бессмысленно для текста (мы могли бы добавить лигатуры в список нарушителей). Тем не менее, поскольку люди привыкли к вкладкам и контролю символов, занимающих одну единицу длины, кодовые точки были бы более интуитивно понятной мерой. О, и спасибо за правильный ответ, грустно видеть это так далеко внизу :-(
masaers

3
@LF немного лучше. Но так много вещей до сих пор не охвачено: toupperи tolowerвсе еще работают над отдельными персонажами. Класс строки все еще не имеет понятия нормализации (например, кодируется ли «ü» как «u с диарезом» или «u + комбинирующий диарез») или где строка может быть или не быть разделена. Список можно продолжить. Строка u8string (как и другие стандартные классы строк) подходит для "прохождения". Но если вы хотите обработать Unicode, вам нужен ICU.
DevSolar

36

Используя основанный на диапазоне цикл 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);
}

9
Однако на французском компьютере эта программа не преобразует символы, не входящие в ASCII, разрешенные на французском языке. Например, строка «Test String123. É Ï \ n 'будет преобразовано в:' тестовая строка123. É Ï \ n ', хотя символы É Ï и их строчные буквы' é 'и' ï 'разрешены на французском языке. Похоже, что другие сообщения этой темы не нашли решения для этого.
Резает

Я думаю, что вам нужно установить правильную локаль для этого.
user1095108

@incises, тогда кто-то опубликовал ответ о ICU, и это, безусловно, путь. Проще, чем большинство других решений, которые будут пытаться понять язык.
Алексис Уилк

Я бы предпочел не использовать внешние библиотеки, когда это возможно, лично.
kayleeFrye_onDeck


15

Это продолжение ответа Стефана Май: если вы хотите поместить результат преобразования в другую строку, вам необходимо предварительно выделить место для хранения перед вызовом std::transform. Поскольку STL сохраняет преобразованные символы в итераторе назначения (увеличивая его на каждой итерации цикла), размер строки назначения не будет автоматически изменяться, и вы рискуете переполнить память.

#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;
}

1
Это не
изменило

Здесь также можно использовать итератор с обратной вставкой вместо ручного изменения размера.
перец чили

11

Другой подход с использованием диапазона на основе для цикла с контрольной переменной

string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

cout<<test<<endl;

6

Насколько я вижу, библиотеки Boost действительно плохо влияют на производительность. Я проверил их unordered_map в STL, и в среднем он был в 3 раза медленнее (лучший случай 2, худший - 10 раз). Также этот алгоритм выглядит слишком низким.

Разница настолько велика, что я уверен, что любое дополнение, которое вам нужно сделать, tolowerчтобы сделать его равным ускорению «для ваших нужд», будет намного быстрее чем буст.

Я провел эти тесты на Amazon EC2, поэтому производительность менялась во время теста, но вы все еще поняли.

./test
Elapsed time: 12365milliseconds
Elapsed time: 1640milliseconds
./test
Elapsed time: 26978milliseconds
Elapsed time: 1646milliseconds
./test
Elapsed time: 6957milliseconds
Elapsed time: 1634milliseconds
./test
Elapsed time: 23177milliseconds
Elapsed time: 2421milliseconds
./test
Elapsed time: 17342milliseconds
Elapsed time: 14132milliseconds
./test
Elapsed time: 7355milliseconds
Elapsed time: 1645milliseconds

-O2 сделал это так:

./test
Elapsed time: 3769milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3815milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3643milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 22018milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 3845milliseconds
Elapsed time: 569milliseconds

Источник:

string str;
bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    boost::algorithm::to_lower(str);
}
bench.end();

bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    for(unsigned short loop=0;loop < str.size();loop++)
    {
        str[loop]=tolower(str[loop]);
    }
}
bench.end();

Я предполагаю, что мне следует пройти тесты на выделенной машине, но я буду использовать этот EC2, поэтому мне не нужно тестировать его на моей машине.


1
Открывали ли вы опции оптимизации при его компиляции? Я думаю, что библиотека STL Boost должна работать лучше с высоким уровнем оптимизации.
Вэй Сонг

1
Я использовал -O2 в одном из тестов и больше ничего.
Etherealone

2
Производительность unordered_map зависит от алгоритма хеширования в сочетании с данными, которые вы используете. Не существует волшебного алгоритма хеширования, который бы работал для всех и любых данных, чтобы сделать unordered_map как можно быстрее. Оценивайте и пробуйте разные вещи. Причина того, что производительность ухудшается, заключается в том, что при использовании хэша вы получаете много коллизий, что в основном вызывает поиск в списке. Посетите этот сайт для получения дополнительной информации: fgda.pl/post/7/gcc-hash-map-vs-unordered-map. В моих целях функция, предоставленная по ссылке, уменьшала коллизии и, следовательно, была очень быстрой.
leetNightshade

6

Простейший способ преобразовать строку в 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;
}

5

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() )для оператора?
квазар

Для константной строки мы можем просто сделать локальную копию и затем преобразовать ее на место.
Самер

Да, хотя, создание копии добавляет больше накладных расходов.
квазар

Вы можете использовать std :: transform с версией ctype :: tolower, которая не принимает указатели. Используйте адаптер итератора с обратной вставкой, и вам даже не нужно беспокоиться о предварительном изменении размера выходной строки.
перец чили

Отлично, особенно потому, что в libstdc ++ tolowerс localeпараметром неявный вызов use_facetявляется узким местом производительности. Один из моих коллег добился увеличения скорости на несколько 100%, заменив boost::iequals(что имеет эту проблему) версией, которая use_facetвызывается только один раз за пределами цикла.
Арне Фогель

3

Альтернативой Boost является POCO (pocoproject.org).

POCO предлагает два варианта:

  1. Первый вариант делает копию без изменения исходной строки.
  2. Второй вариант изменяет исходную строку на месте.
    Версии «на месте» всегда имеют «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);

3

Есть способ преобразовать верхний регистр в нижний БЕЗ выполнения тестов , и это довольно просто. Использование функции / макроса 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;
}

Этот подход, в то же время, позволит вам переназначить любые другие символы, которые вы хотите изменить.

Этот подход имеет одно огромное преимущество при работе на современных процессорах: нет необходимости делать предсказание ветвления, поскольку нет тестов, содержащих ветвление. Это сохраняет логику предсказания ветвления ЦП для других циклов и предотвращает задержки конвейера.

Некоторые здесь могут признать этот подход тем же, который использовался для преобразования EBCDIC в ASCII.


2
«Есть способ преобразовать верхний регистр в нижний БЕЗ выполнения, если тесты» когда-либо слышали о таблицах поиска?
Габор Буэлла

1
Неопределенное поведение для отрицательных символов.
Роланд Иллиг

Современные процессоры являются узким местом в памяти, а не процессором. Бенчмаркинг будет интересным.
Контанго

3

Поскольку ни в одном из ответов не упоминалась будущая библиотека Ranges, которая доступна в стандартной библиотеке начиная с C ++ 20 и в настоящее время отдельно доступна на GitHub as 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); });

(Не забудьте #include <cctype>и требуемые заголовки диапазонов.)

Примечание: использование в unsigned charкачестве аргумента лямбды основано на cppreference , который гласит:

Как и у всех других функций <cctype>, поведение std::tolowerне определено, если значение аргумента не может быть представлено unsigned charили равно EOF. Чтобы безопасно использовать эти функции с обычными chars (или signed chars), аргумент должен быть сначала преобразован в unsigned char:

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

Точно так же они не должны напрямую использоваться со стандартными алгоритмами, когда тип значения итератора равен 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;
}

3

Мой собственный шаблон функций, который выполняет верхний / нижний регистр.

#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(), tolower);
    return std::move(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(), toupper);
    return std::move(s2);
}

Это то, что мне было нужно. Я просто использовал towlowerдля широких символов, который поддерживает UTF-16.
Juv

2

Вот метод макроса, если вы хотите что-то простое:

#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.


1
Я опровергаю это за предоставление макросов, когда существует совершенно хорошее решение - вы даже даете эти решения.
Яснее

2
Макро-техника означает меньше набирать код для чего-то, что обычно используется в программировании. Почему бы не использовать это? Иначе зачем вообще есть макросы?
Volomike

3
Макросы - это наследие C, от которого усиленно трудятся, чтобы избавиться от них. Если вы хотите уменьшить объем печати, используйте функцию или лямбду. void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
Яснее

1
@Clearer Поскольку я хочу стать лучшим программистом, можете ли вы предоставить мне какие-либо ссылки на документы ANSI, где какие-либо комитеты ANSI C ++ говорят что-то вроде: «Нам нужно созвать собрание, чтобы избавиться от макросов из C ++»? Или какой-то другой план?
Volomike

2
Нет не могу Позиция Бьярне по этой теме была несколько ясно изложена. Кроме того, есть много причин не использовать макросы в C и C ++. xможет быть допустимым выражением, которое просто правильно компилируется, но из-за макросов даст совершенно фиктивные результаты.
Яснее

2
// 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/


2

Есть ли альтернатива, которая работает 100% времени?

нет

Есть несколько вопросов, которые вы должны задать себе, прежде чем выбрать метод в нижнем регистре.

  1. Как строка закодирована? простой ASCII? UTF-8? какая-то форма расширенного унаследованного кодирования ASCII?
  2. Что вы подразумеваете под строчными? Правила отображения дел варьируются в зависимости от языка! Вы хотите что-то, что локализовано в локали пользователей? Вы хотите что-то, что ведет себя согласованно на всех системах, на которых работает ваше программное обеспечение? Вы просто хотите использовать символы ASCII в нижнем регистре и проходить через все остальное?
  3. Какие библиотеки доступны?

Получив ответы на эти вопросы, вы можете начать искать решение, которое соответствует вашим потребностям. Не существует одного размера, который подходит всем, кто работает везде!


2

Попробуйте эту функцию :)

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;
}

1

На платформах Microsoft вы можете использовать strlwrсемейство функций: http://msdn.microsoft.com/en-us/library/hkxwh33z.aspx

// 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 );
}

0

Фрагмент кода

#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;
}


0

Скопируйте, потому что было запрещено улучшать ответ. Спасибо ТАК


string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

Объяснение:

for(auto& c : test)представляет собой диапазон на основе цикла такого типа :
for (range_declaration:range_expression)loop_statement

  1. range_declaration: auto& c
    Здесь автоматический спецификатор используется для автоматического вывода типа. Таким образом, тип вычитается из инициализатора переменных.

  2. range_expression: test
    Диапазон в этом случае - символы строки test.

Символы строки testдоступны в качестве ссылки внутри цикла for с идентификатором c.


Пожалуйста, уточните, откуда вы скопировали свой ответ.
bfontaine

0

C ++ не имеет методов tolower или toupper для строки, но он доступен для char. Можно легко прочитать каждый символ строки, преобразовать его в нужный регистр и вернуть обратно в строку. Пример кода без использования сторонней библиотеки:

#include<iostream>

int main(){
  std::string str = std::string("How IS The Josh");
  for(char &ch : str){
    ch = std::tolower(ch);
  }
  std::cout<<str<<std::endl;
  return 0;
}

Для символьной операции над строкой: для каждого символа в строке


-1

Это может быть еще одна простая версия для преобразования прописных букв в строчные и наоборот. Я использовал версию сообщества VS2017 для компиляции этого исходного кода.

#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;
}

Примечание: если есть специальные символы, то их нужно обрабатывать с помощью проверки состояния.


-8

Я пробовал std :: transform, все, что я получаю, это отвратительная ошибка компиляции stl, которую могут понять только друиды 200 лет назад (не может конвертировать из в flibidi flabidi flu)

это прекрасно работает и может быть легко настроено

string LowerCase(string s)
{
    int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='A')&&(s[i]<='Z'))
            s[i]+=dif;
    }
   return s;
}

string UpperCase(string s)
{
   int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='a')&&(s[i]<='z'))
            s[i]-=dif;
    }
   return s;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.