Преобразование строки в С++ в верхний регистр

Как можно преобразовать строку в верхний регистр. Примеры, которые я нашел из googling, имеют дело только с символами.

Ответ 1

Ускоряем строковые алгоритмы:

#include <boost/algorithm/string.hpp>
#include <string>

std::string str = "Hello World";

boost::to_upper(str);

std::string newstr = boost::to_upper_copy<std::string>("Hello World");

Ответ 2

#include <algorithm>
#include <string>

std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);

Ответ 3

Краткое решение с использованием С++ 11 и toupper().

for (auto & c: str) c = toupper(c);

Ответ 4

struct convert {
   void operator()(char& c) { c = toupper((unsigned char)c); }
};

// ... 
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());

Примечание. Пара проблем с верхним решением:

21.5 Утилит последовательности с нулевым завершением

Содержимое этих заголовков должно быть таким же, как и заголовки стандартной библиотеки C < ctype.h > , < wctype.h > , < string.h > , < wchar.h > , < stdlib.h > [...]

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

  • Другая проблема с тем же примером состоит в том, что он не передает аргумент или не проверяет, что это неотрицательно; это особенно опасно для систем, в которых подписан знак char. (Причина: если это реализовано как макрос, он, вероятно, будет использовать таблицу поиска и индексы аргументов в эту таблицу. Отрицательный индекс даст вам UB.)

Ответ 5

Эта проблема векторизована с SIMD для набора символов ASCII.


Сравнение ускорений:

Предварительное тестирование с x86-64 gcc 5.2 -O3 -march=native на Core2Duo (Merom). Одна и та же строка из 120 символов (смешанный ASCII в нижнем и нижнем регистре), преобразованная в цикле 40M раз (без встраивания между файлами, поэтому компилятор не может оптимизировать его или вывести из цикла). Одинаковые буферы source и dest, поэтому никаких накладных расходов malloc или эффектов памяти/кэша: данные все время находятся в кеше L1, и мы полностью привязаны к процессору.

  • boost::to_upper_copy<char*, std::string>(): 198,0 с. Да, Boost 1.58 на Ubuntu 15.10 действительно такой медленный. Я профилировал и пошагово ассемблировал asm в отладчике, и это действительно, очень плохо: там происходит динамическая переменная локали для каждого символа !!! (dynamic_cast принимает несколько вызовов strcmp). Это происходит с LANG=C и с LANG=en_CA.UTF-8.

    Я не тестировал использование RangeT, кроме std::string. Возможно, другая форма to_upper_copy оптимизирует лучше, но я думаю, что всегда будет new/malloc место для копии, поэтому ее сложнее тестировать. Возможно, что-то, что я сделал, отличается от обычного варианта использования, и, возможно, обычно остановленный g++ может вывести настройки локали из цикла для каждого символа. Мой цикл чтения из std::string и записи в char dstbuf[4096] имеет смысл для тестирования.

  • цикл, вызывающий glibc toupper: 6,67 с (однако не проверяет результат int для потенциального многобайтового UTF-8. Это важно для турецкого языка.)

  • Цикл только для ASCII: 8,79 с (моя базовая версия для результатов, приведенных ниже.) Очевидно, поиск в таблице происходит быстрее, чем cmov, в любом случае таблица горячая в L1.
  • Только в ASCII-векторизации: 2,51 с. (120 символов - это на полпути между худшим и лучшим случаями, см. ниже)
  • Векторизация только для ASCII: 1,35 с

См. также этот вопрос о том, что toupper() работает медленно в Windows, когда задан языковой стандарт.


Я был шокирован, что Boost на порядок медленнее, чем другие варианты. Я дважды проверил, что я включил -O3, и даже пошагово осел, чтобы посмотреть, что он делает. Это почти точно такая же скорость с кланом g++ 3.8. Это имеет огромные накладные расходы внутри цикла за символ. Результат perf record/report (для события perf cycles):

  32.87%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNK10__cxxabiv121__vmi_class_type_info12__do_dyncastElNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16
  21.90%  flipcase-clang-  libstdc++.so.6.0.21   [.] __dynamic_cast                                                                                                 
  16.06%  flipcase-clang-  libc-2.21.so          [.] __GI___strcmp_ssse3                                                                                            
   8.16%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale                                                                     
   7.84%  flipcase-clang-  flipcase-clang-boost  [.] _Z16strtoupper_boostPcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE                                   
   2.20%  flipcase-clang-  libstdc++.so.6.0.21   [.] [email protected]                                                                                                     
   2.15%  flipcase-clang-  libstdc++.so.6.0.21   [.] [email protected]                                                                                             
   2.14%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt6locale2id5_M_idEv                                                                                       
   2.11%  flipcase-clang-  libstdc++.so.6.0.21   [.] [email protected]                                                                                   
   2.08%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt5ctypeIcE10do_toupperEc                                                                                  
   2.03%  flipcase-clang-  flipcase-clang-boost  [.] [email protected]                                                                 
   0.08% ...

Автовекторизация

Gcc и clang будут автоматически векторизовывать циклы только тогда, когда число итераций известно перед циклом. (то есть поисковые циклы, такие как реализация strlen на обычном C, не будут автоматически векторизованы.)

Таким образом, для строк, достаточно маленьких для размещения в кеше, мы получаем значительное ускорение для строк длиной ~ 128 символов, выполняя сначала strlen. Это не будет необходимо для строк с явной длиной (например, C++ std::string).

// char, not int, is essential: otherwise gcc unpacks to vectors of int!  Huge slowdown.
char ascii_toupper_char(char c) {
    return ('a' <= c && c <= 'z') ? c^0x20 : c;    // ^ autovectorizes to PXOR: runs on more ports than paddb
}

// gcc can only auto-vectorize loops when the number of iterations is known before the first iteration.  strlen gives us that
size_t strtoupper_autovec(char *dst, const char *src) {
    size_t len = strlen(src);
    for (size_t i=0 ; i<len ; ++i) {
        dst[i] = ascii_toupper_char(src[i]);  // gcc does the vector range check with psubusb / pcmpeqb instead of pcmpgtb
    }
    return len;
}

Любой приличный libc будет иметь эффективный strlen намного быстрее, чем зацикливание байта за раз, поэтому отдельные векторизованные циклы strlen и toupper работают быстрее.

Базовая линия: цикл, который проверяет завершающий 0 на лету.

Время для 40M итераций на Core2 (Merom) 2,4 ГГц. GCC 5,2 -O3 -march=native. (Ubuntu 15.10). dst != src (поэтому мы делаем копию), но они не пересекаются (и не находятся рядом). Оба выровнены.

  • 15 символьная строка: базовая линия: 1,08 с. autovec: 1,34 с
  • 16 символьная строка: базовая линия: 1,16 с. autovec: 1,52 с
  • 127 символьная строка: базовый уровень: 8,91 с. autovec: 2.98s//не векторная очистка имеет 15 символов для обработки
  • 128 символьная строка: базовый уровень: 9,00 с. autovec: 2.06 с
  • 129 символьная строка: базовая линия: 9.04 с. autovec: 2.07s//не векторная очистка имеет 1 символ для обработки

Некоторые результаты немного отличаются от Clang.

Цикл микробенчмарка, который вызывает функцию, находится в отдельном файле. В противном случае он встроен, и strlen() выводится из цикла, и он работает значительно быстрее, особенно для 16 строк символов (0,187 с).

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


Так что есть большие ускорения, но автоматическая векторизация компилятора не делает отличный код, особенно. для очистки последних до 15 символов.

Ручная векторизация с использованием встроенных функций SSE:

Основан на моей функции переключения регистра, которая инвертирует регистр каждого алфавитного символа. Он использует "трюк сравнения без знака", при котором вы можете выполнить low < a && a <= high с одним сравнением без знака путем сдвига диапазона, так что любое значение, меньшее low, будет преобразовано в значение, большее, чем high. (Это работает, если low и high не слишком далеко друг от друга.)

SSE имеет только подписанное сравнение-большее, но мы все еще можем использовать "без знака" сравните трюк путем смещения диапазона до нижней части диапазона со знаком: вычтите 'a' +128, чтобы буквенные символы варьировались от -128 до -128 +25 (-128 + 'z' - 'a' )

Обратите внимание, что сложение 128 и вычитание 128 - это то же самое для 8-битных целых чисел. Керри некуда идти, так что это просто xor (добавить без переноса), щелкнув старшим битом.

#include <immintrin.h>

__m128i upcase_si128(__m128i src) {
    // The above 2 paragraphs were comments here
    __m128i rangeshift = _mm_sub_epi8(src, _mm_set1_epi8('a'+128));
    __m128i nomodify   = _mm_cmpgt_epi8(rangeshift, _mm_set1_epi8(-128 + 25));  // 0:lower case   -1:anything else (upper case or non-alphabetic).  25 = 'z' - 'a'

    __m128i flip  = _mm_andnot_si128(nomodify, _mm_set1_epi8(0x20));            // 0x20:lcase    0:non-lcase

    // just mask the XOR-mask so elements are XORed with 0 instead of 0x20
    return          _mm_xor_si128(src, flip);
    // it easier to xor with 0x20 or 0 than to AND with ~0x20 or 0xFF
}

Учитывая эту функцию, которая работает для одного вектора, мы можем вызвать ее в цикле для обработки всей строки. Поскольку мы уже нацелены на SSE2, мы можем одновременно выполнять векторизованную проверку конца строки.

Мы также можем сделать намного лучше для "очистки" последних до 15 байтов, оставшихся после выполнения векторов 16B: верхний регистр идемпотентен, поэтому повторная обработка некоторых входных байтов в порядке. Мы делаем невыровненную загрузку последних 16B источника и сохраняем ее в буфере dest, перекрывающем последнее 16B хранилище из цикла.

Единственный раз, когда это не работает, это когда вся строка меньше 16B: даже когда dst=src неатомарное чтение-изменение-запись это не то же самое, что совсем не трогать некоторые байты, и может нарушать многопоточный код.

Для этого у нас есть скалярная петля, а также чтобы выровнять src. Так как мы не знаем, где будет завершающий 0, не выровненная загрузка из src может перейти на следующую страницу и вызвать ошибку. Если нам нужны какие-либо байты в выровненном фрагменте 16B, всегда безопасно загрузить весь выровненный фрагмент 16B.

Полный источник: в github gist.

// FIXME: does not always copy the terminating 0.
// microbenchmarks are for this version of the code (with _mm_store in the loop, instead of storeu, for Merom).
size_t strtoupper_sse2(char *dst, const char *src_begin) {
    const char *src = src_begin;
    // scalar until the src pointer is aligned
    while ( (0xf & (uintptr_t)src) && *src ) {
        *(dst++) = ascii_toupper(*(src++));
    }

    if (!*src)
        return src - src_begin;

    // current position (p) is now 16B-aligned, and we're not at the end
    int zero_positions;
    do {
        __m128i sv = _mm_load_si128( (const __m128i*)src );
        // TODO: SSE4.2 PCMPISTRI or PCMPISTRM version to combine the lower-case and '\0' detection?

        __m128i nullcheck = _mm_cmpeq_epi8(_mm_setzero_si128(), sv);
        zero_positions = _mm_movemask_epi8(nullcheck);
        // TODO: unroll so the null-byte check takes less overhead
        if (zero_positions)
            break;

        __m128i upcased = upcase_si128(sv);   // doing this before the loop break lets gcc realize that the constants are still in registers for the unaligned cleanup version.  But it leads to more wasted insns in the early-out case

        _mm_storeu_si128((__m128i*)dst, upcased);
        //_mm_store_si128((__m128i*)dst, upcased);  // for testing on CPUs where storeu is slow
        src += 16;
        dst += 16;
    } while(1);

    // handle the last few bytes.  Options: scalar loop, masked store, or unaligned 16B.
    // rewriting some bytes beyond the end of the string would be easy,
    // but doing a non-atomic read-modify-write outside of the string is not safe.
    // Upcasing is idempotent, so unaligned potentially-overlapping is a good option.

    unsigned int cleanup_bytes = ffs(zero_positions) - 1;  // excluding the trailing null
    const char* last_byte = src + cleanup_bytes;  // points at the terminating '\0'

    // FIXME: copy the terminating 0 when we end at an aligned vector boundary
    // optionally special-case cleanup_bytes == 15: final aligned vector can be used.
    if (cleanup_bytes > 0) {
        if (last_byte - src_begin >= 16) {
            // if src==dest, this load overlaps with the last store:  store-forwarding stall.  Hopefully OOO execution hides it
            __m128i sv = _mm_loadu_si128( (const __m128i*)(last_byte-15) ); // includes the \0
            _mm_storeu_si128((__m128i*)(dst + cleanup_bytes - 15), upcase_si128(sv));
        } else {
            // whole string less than 16B
            // if this is common, try 64b or even 32b cleanup with movq / movd and upcase_si128
#if 1
            for (unsigned int i = 0 ; i <= cleanup_bytes ; ++i) {
                dst[i] = ascii_toupper(src[i]);
            }
#else
            // gcc stupidly auto-vectorizes this, resulting in huge code bloat, but no measurable slowdown because it never runs
            for (int i = cleanup_bytes - 1 ;  i >= 0 ; --i) {
                dst[i] = ascii_toupper(src[i]);
            }
#endif
        }
    }

    return last_byte - src_begin;
}

Время для 40M итераций на Core2 (Merom) 2,4 ГГц. GCC 5,2 -O3 -march=native. (Ubuntu 15.10). dst != src (поэтому мы делаем копию), но они не пересекаются (и не находятся рядом). Оба выровнены.

  • 15 символьная строка: базовая линия: 1,08 с. Autovec: 1,34 с. руководство: 1,29 с
  • 16 символьная строка: базовая линия: 1,16 с. Autovec: 1,52 с. руководство: 0,335 с
  • 31 символьная строка: инструкция: 0,479 с
  • 127 символьная строка: базовый уровень: 8,91 с. Autovec: 2,98 с. руководство: 0,925 с
  • 128 символьная строка: базовый уровень: 9,00 с. Autovec: 2,06 с. руководство: 0,931 с
  • 129 символьная строка: базовая линия: 9.04 с. Autovec: 2,07 с. руководство: 1.02 с

(Фактически приурочен к _mm_store в цикле, а не к _mm_storeu, потому что storeu медленнее на Merom, даже когда адрес выровнен. Это хорошо на Nehalem и позже. Я также оставил код как есть на данный момент, вместо этого исправления ошибки в некоторых случаях, когда я не копирую завершающий 0, потому что я не хочу все время менять.)

Таким образом, для коротких строк длиннее 16В это значительно быстрее, чем векторизация. Длина на единицу меньше ширины вектора не представляет проблемы. Они могут быть проблемой при работе на месте из-за остановки магазина. (Но учтите, что обрабатывать наш собственный вывод все же хорошо, а не исходный ввод, потому что toupper является идемпотентом).

Существует много возможностей для настройки этого для различных вариантов использования, в зависимости от того, что хочет окружающий код, и целевой микроархитектуры. Заставить компилятор выдавать хороший код для части очистки довольно сложно. Использование ffs(3) (которое компилируется в bsf или tzcnt на x86) кажется хорошим, но очевидно, что этот бит нуждается в переосмыслении, так как я заметил ошибку после написания большей части этого ответа (см. комментарии FIXME).

Векторные ускорения для еще меньших струн можно получить с помощью загрузок/накопителей movq или movd. Настройте по мере необходимости для вашего варианта использования.


UTF-8:

Мы можем определить, когда в нашем векторе есть байты с установленным старшим битом, и в этом случае вернуться к скалярному циклу с поддержкой utf-8 для этого вектора. Точка dst может перемещаться на величину, отличную от указателя src, но как только мы вернемся к выровненному указателю src, мы все равно будем просто делать невыровненные векторные хранилища в dst.

Для текста, который UTF-8, но в основном состоит из подмножества ASCII UTF-8, это может быть хорошо: высокая производительность в общем случае с корректным поведением во всех случаях. Однако, когда в нем много не ASCII, это, вероятно, будет хуже, чем постоянное пребывание в скалярном цикле с поддержкой UTF-8.

Ускорение английского за счет других языков не является решением на будущее, если недостаток существенный.


Локали известно:

В турецком языке (tr_TR) правильный результат из toupper('i') - 'İ' (U0130), а не 'I' (обычный ASCII). Мартин Боннер комментирует вопрос о медленной работе tolower() в Windows.

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

С такой большой сложностью SSE4.2 PCMPISTRM или что-то может сделать много наших проверок за один раз.

Ответ 6

У вас есть символы ASCII или International в строках?

Если это последний случай, "верхний регистр" не так прост и зависит от используемого алфавита. Существуют двухпалатные и однокамерные алфавиты. Только двухпалатные алфавиты имеют разные символы для верхнего и нижнего регистра. Кроме того, есть составные символы, такие как латинская буква "DZ" (\ u01F1 'DZ'), которые используют так называемый заголовок. Это означает, что изменяется только первый символ (D).

Я предлагаю вам посмотреть ICU и разницу между простыми и полными отображениями случаев. Это может помочь:

http://userguide.icu-project.org/transforms/casemappings

Ответ 7

string StringToUpper(string strToConvert)
{
   for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
       *p = toupper(*p);

   return p;
}

Или

string StringToUpper(string strToConvert)
{
    std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);

    return strToConvert;
}

Ответ 8

Чем быстрее , если вы используете только символы ASCII:

for(i=0;str[i]!=0;i++)
  if(str[i]<='z' && str[i]>='a')
    str[i]-=32;

Обратите внимание, что этот код работает быстрее, но работает только в ASCII и не является "абстрактным" решением.

Если вам нужны решения UNICODE или более традиционные и абстрактные решения, перейдите к другим ответам и поработайте с методами строк C++.

Ответ 9

Используйте лямбда.

std::string s("change my case");

auto to_upper = [] (char_t ch) { return std::use_facet<std::ctype<char_t>>(std::locale()).toupper(ch); };

std::transform(s.begin(), s.end(), s.begin(), to_upper);

Ответ 10

Следующее работает для меня.

#include <algorithm>
void  toUpperCase(std::string& str)
{
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

int main()
{
   std::string str = "hello";
   toUpperCase(&str);
}

Ответ 11

//works for ASCII -- no clear advantage over what is already posted...

std::string toupper(const std::string & s)
{
    std::string ret(s.size(), char());
    for(unsigned int i = 0; i < s.size(); ++i)
        ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i];
    return ret;
}

Ответ 12

Пока вы в порядке с ASCII-only и можете предоставить действительный указатель на память RW, в C есть простая и очень эффективная однострочная строка:

void strtoupper(char* str)
{ 
    while (*str) *(str++) = toupper((unsigned char)*str);
}

Это особенно хорошо для простых строк, таких как идентификаторы ASCII, которые вы хотите нормализовать в том же регистре символов. Затем вы можете использовать буфер для создания экземпляра std: string.

Ответ 13

#include <string>
#include <locale>

std::string str = "Hello World!";
auto & f = std::use_facet<std::ctype<char>>(std::locale());
f.toupper(str.data(), str.data() + str.size());

Это будет работать лучше, чем все ответы, которые используют глобальную функцию toupper, и, по-видимому, это то, что делает boost:: to_upper.

Это потому, что:: toupper должен искать локаль - потому что он мог быть изменен другим потоком - для каждого вызова, тогда как здесь только вызов locale() имеет это наказание. И поиск языка обычно предполагает фиксацию.

Это также работает с С++ 98 после замены auto, использования новой неконстантной str.data() и добавления пробела для разрыва закрытия шаблона ( " → " на " → " ) например:

std::use_facet<std::ctype<char> > & f = 
    std::use_facet<std::ctype<char> >(std::locale());
f.toupper(const_cast<char *>(str.data()), str.data() + str.size());

Ответ 14

typedef std::string::value_type char_t;

char_t up_char( char_t ch )
{
    return std::use_facet< std::ctype< char_t > >( std::locale() ).toupper( ch );
}

std::string toupper( const std::string &src )
{
    std::string result;
    std::transform( src.begin(), src.end(), std::back_inserter( result ), up_char );
    return result;
}

const std::string src  = "test test TEST";

std::cout << toupper( src );

Ответ 15

std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
    *p = toupper(*p);

Ответ 16

попробуйте функцию toupper() (#include <ctype.h>). он принимает символы в качестве аргументов, строки состоят из символов, поэтому вам придется перебирать каждый отдельный символ, который при объединении содержит строку

Ответ 17

Вот последний код с С++ 11

std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });

Ответ 18

Не уверен, что есть встроенная функция. Попробуйте следующее:

Включите библиотеки ctype.h ИЛИ cctype, а также stdlib.h как часть директив препроцессора.

string StringToUpper(string strToConvert)
{//change each element of the string to upper case
   for(unsigned int i=0;i<strToConvert.length();i++)
   {
      strToConvert[i] = toupper(strToConvert[i]);
   }
   return strToConvert;//return the converted string
}

string StringToLower(string strToConvert)
{//change each element of the string to lower case
   for(unsigned int i=0;i<strToConvert.length();i++)
   {
      strToConvert[i] = tolower(strToConvert[i]);
   }
   return strToConvert;//return the converted string
}

Ответ 19

Мое решение (очистка 6-го бита для альфы):

#include <ctype.h>

inline void toupper(char* str)
{
    while (str[i]) {
        if (islower(str[i]))
            str[i] &= ~32; // Clear bit 6 as it is what differs (32) between Upper and Lowercases
        i++;
    }
}

Ответ 20

Использование Boost.Text, который будет работать с текстом Unicode

boost::text::text t = "Hello World";
boost::text::text uppered;
boost::text::to_title(t, std::inserter(uppered, uppered.end()));
std::string newstr = uppered.extract();

Ответ 21

Все эти решения на этой странице сложнее, чем они должны быть.

Сделайте это

RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
     RegName[forLoop] = tolower(RegName[forLoop]);
}

RegName - ваш string. Получите свой размер строки, не используйте string.size() как ваш фактический тестер, очень грязный и может вызвать проблемы. тогда. самый простой цикл for.

помните, что размер строки возвращает разделитель, поэтому используйте < а не <= в тесте цикла.

вывод будет: некоторые строки, которые вы хотите преобразовать

Ответ 22

Без использования каких-либо библиотек:

std::string YourClass::Uppercase(const std::string & Text)
{
    std::string UppperCaseString;
    UppperCaseString.reserve(Text.size());
    for (std::string::const_iterator it=Text.begin(); it<Text.end(); ++it)
    {
        UppperCaseString.push_back(((0x60 < *it) && (*it < 0x7B)) ? (*it - static_cast<char>(0x20)) : *it);
    }
    return UppperCaseString;
}

Ответ 23

Если вас интересуют только 8-битные символы (которые также принимают все другие ответы, кроме Милана Бабушкова), вы можете получить максимальную скорость, создав таблицу поиска во время компиляции, используя метапрограммирование. На ideone.com это работает на 7 раз быстрее, чем библиотечная функция, и на 3 раза быстрее, чем написанная вручную версия (http://ideone.com/sb1Rup). Он также настраивается с помощью признаков без замедления.

template<int ...Is>
struct IntVector{
using Type = IntVector<Is...>;
};

template<typename T_Vector, int I_New>
struct PushFront;
template<int ...Is, int I_New>
struct PushFront<IntVector<Is...>,I_New> : IntVector<I_New,Is...>{};

template<int I_Size, typename T_Vector = IntVector<>>
struct Iota : Iota< I_Size-1, typename PushFront<T_Vector,I_Size-1>::Type> {};
template<typename T_Vector>
struct Iota<0,T_Vector> : T_Vector{};

template<char C_In>
struct ToUpperTraits {
    enum { value = (C_In >= 'a' && C_In <='z') ? C_In - ('a'-'A'):C_In };
};

template<typename T>
struct TableToUpper;
template<int ...Is>
struct TableToUpper<IntVector<Is...>>{
    static char at(const char in){
        static const char table[] = {ToUpperTraits<Is>::value...};
        return table[in];
    }
};

int tableToUpper(const char c){
    using Table = TableToUpper<typename Iota<256>::Type>;
    return Table::at(c);
}

с использованием:

std::transform(in.begin(),in.end(),out.begin(),tableToUpper);

Для углубленного (многостраничного) описания того, как это работает, позвольте мне бесстыдно подключить мой блог: http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html

Ответ 24

template<size_t size>
char* toupper(char (&dst)[size], const char* src) {
    // generate mapping table once
    static char maptable[256];
    static bool mapped;
    if (!mapped) {
        for (char c = 0; c < 256; c++) {
            if (c >= 'a' && c <= 'z')
                maptable[c] = c & 0xdf;
            else
                maptable[c] = c;
        }
        mapped = true;
    }

    // use mapping table to quickly transform text
    for (int i = 0; *src && i < size; i++) {
        dst[i] = maptable[*(src++)];
    }
    return dst;
}

Ответ 25

Эта функция c++ всегда возвращает строку верхнего регистра...

#include <locale> 
#include <string>
using namespace std; 
string toUpper (string str){
    locale loc; 
    string n; 
    for (string::size_type i=0; i<str.length(); ++i)
        n += toupper(str[i], loc);
    return n;
}

Ответ 26

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

void to_upper(const std::string str) {
    std::string::iterator it;
    int i;
    for ( i=0;i<str.size();++i ) {
        ((char *)(void *)str.data())[i]=toupper(((char *)str.data())[i]);
    }
}

Ответ 27

На всех машинах, которые я тестировал, это было быстрее. Возможно, потому, что он не занимается очень широким спектром персонажей. Или потому, что с помощью switch() он делает таблицу перехода, не знаю, как она работает в сборке... просто знайте, что это быстрее: P

string Utils::String::UpperCase(string CaseString) {
    for (unsigned short i = 0, tamanho = CaseString.length(); i < tamanho; i++) {
        switch (CaseString[i]) {
            case 'a':
                CaseString[i] = 'A';
                break;
            case 'b':
                CaseString[i] = 'B';
                break;
            case 'c':
                CaseString[i] = 'C';
                break;
            case 'd':
                CaseString[i] = 'D';
                break;
            case 'e':
                CaseString[i] = 'E';
                break;
            case 'f':
                CaseString[i] = 'F';
                break;
            case 'g':
                CaseString[i] = 'G';
                break;
            case 'h':
                CaseString[i] = 'H';
                break;
            case 'i':
                CaseString[i] = 'I';
                break;
            case 'j':
                CaseString[i] = 'J';
                break;
            case 'k':
                CaseString[i] = 'K';
                break;
            case 'l':
                CaseString[i] = 'L';
                break;
            case 'm':
                CaseString[i] = 'M';
                break;
            case 'n':
                CaseString[i] = 'N';
                break;
            case 'o':
                CaseString[i] = 'O';
                break;
            case 'p':
                CaseString[i] = 'P';
                break;
            case 'q':
                CaseString[i] = 'Q';
                break;
            case 'r':
                CaseString[i] = 'R';
                break;
            case 's':
                CaseString[i] = 'S';
                break;
            case 't':
                CaseString[i] = 'T';
                break;
            case 'u':
                CaseString[i] = 'U';
                break;
            case 'v':
                CaseString[i] = 'V';
                break;
            case 'w':
                CaseString[i] = 'W';
                break;
            case 'x':
                CaseString[i] = 'X';
                break;
            case 'y':
                CaseString[i] = 'Y';
                break;
            case 'z':
                CaseString[i] = 'Z';
                break;
        }
    }
    return CaseString;
}