Как можно преобразовать строку в верхний регистр. Примеры, которые я нашел из поиска в Google, имеют дело только с символами.
Как можно преобразовать строку в верхний регистр. Примеры, которые я нашел из поиска в Google, имеют дело только с символами.
Ответы:
Алгоритмы ускорения строк:
#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");
std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
#include <algorithm>
#include <string>
std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
toupper()
может быть реализовано в виде макроса. Это может вызвать проблему.
toupper
. Любые идеи?
Краткое решение с использованием C ++ 11 и toupper ().
for (auto & c: str) c = toupper(c);
c
будет const char
типа (с auto
)? Если это так, вы не можете присвоить его (из-за const
части) тому, что возвращается toupper(c)
.
c
необходимо использовать его unsigned char
для исправления.
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
подписано plain . (Причина в том, что если это будет реализовано в виде макроса, он, вероятно, будет использовать таблицу поиска и ваши индексы аргументов в этой таблице. Отрицательный индекс даст вам UB.)
Эта проблема векторизована с 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 действительно такой медленный. Я профилировал и пошагово выполнял ассемблер в отладчике, и это очень, очень плохо: есть динамическая переменная локали для каждого символа !!! (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.67s (не проверяя int
результат для потенциального многобайтового UTF-8, хотя. Это важно для турецкого языка.)
cmov
, в любом случае с горячей таблицей в L1.См. Также этот вопрос о toupper()
медленной работе в Windows при заданной локали .
Я был шокирован тем, что Boost на порядок медленнее, чем другие варианты. Я дважды проверил, что я -O3
включил, и даже пошагово осмотрел, чтобы увидеть, что он делает. Это почти точно такая же скорость с Clang ++ 3.8. Это имеет огромные накладные расходы внутри цикла за символ. Результат perf record
/ report
(для cycles
события perf):
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 [.] strcmp@plt
2.15% flipcase-clang- libstdc++.so.6.0.21 [.] __dynamic_cast@plt
2.14% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt6locale2id5_M_idEv
2.11% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt6locale2id5_M_idEv@plt
2.08% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt5ctypeIcE10do_toupperEc
2.03% flipcase-clang- flipcase-clang-boost [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale@plt
0.08% ...
Gcc и clang будут автоматически векторизовывать циклы только тогда, когда счетчик итераций известен перед циклом. (то есть поисковые циклы, такие как реализация на обычном Cstrlen
, не будут автоматически векторизованы.)
Таким образом, для строк, достаточно маленьких, чтобы поместиться в кэш, мы получаем значительное ускорение для строк длиной ~ 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
(поэтому мы делаем копию), но они не пересекаются (и не находятся рядом). Оба выровнены.
Некоторые результаты немного отличаются от Clang.
Цикл микробенчмарка, который вызывает функцию, находится в отдельном файле. В противном случае он встроен иstrlen()
выведен из цикла, и он работает значительно быстрее, особенно. для 16 строк символов (0,187 с).
Это имеет основное преимущество, заключающееся в том, что gcc может автоматически векторизовать его для любой архитектуры, но главный недостаток в том, что он медленнее для обычно распространенного случая небольших строк.
Так что есть большие ускорения, но автоматическая векторизация компилятора не делает отличный код, особенно. для очистки последних до 15 символов.
Основан на моей функции case-flip, которая инвертирует регистр каждого буквенного символа. Он использует «трюк сравнения без знака», при котором вы можете сделать 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's 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: doesn't 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
(поэтому мы делаем копию), но они не пересекаются (и не находятся рядом). Оба выровнены.
(На самом деле приурочен _mm_store
к циклу, нет _mm_storeu
, потому что storeu медленнее на Merom, даже когда адрес выровнен. Это нормально для Nehalem и позже. На данный момент я также оставил код как есть, вместо того, чтобы исправить ошибку копирования завершающий 0 в некоторых случаях, потому что я не хочу переназначать все.)
Таким образом, для коротких строк длиннее 16В это значительно быстрее, чем векторизация. Длина на единицу меньше ширины вектора не представляет проблемы. Они могут быть проблемой при работе на месте из-за остановки магазина. (Но обратите внимание, что все еще нормально обрабатывать наш собственный вывод, а не исходный ввод, потому что toupper является идемпотентом).
Существует много возможностей для настройки этого для различных вариантов использования, в зависимости от того, что хочет окружающий код, и целевой микроархитектуры. Заставить компилятор выдавать хороший код для части очистки сложно. Использование ffs(3)
(которое компилируется в bsf или tzcnt на x86) кажется хорошим, но очевидно, что этот бит нуждается в переосмыслении, так как я заметил ошибку после написания большей части этого ответа (см. Комментарии FIXME).
Векторные ускорения для еще меньших струн можно получить с помощью movq
или movd
загрузить / сохранить. Настройте по мере необходимости для вашего варианта использования.
Мы можем определить, когда в нашем векторе есть байты с установленным старшим битом, и в этом случае вернуться к скалярному циклу с поддержкой 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
или что-то может сделать много наших проверок за один раз.
У вас есть ASCII или международные символы в строках?
Если это последний случай, «верхний регистр» не так прост, и это зависит от используемого алфавита. Существуют двухпалатные и однопалатные алфавиты. Только двухпалатные алфавиты имеют разные символы в верхнем и нижнем регистре. Кроме того, есть составные символы, такие как латинская заглавная буква 'DZ' (\ u01F1 'DZ'), которые используют так называемый регистр заголовка . Это означает, что только первый символ (D) будет изменен.
Я предлагаю вам взглянуть на отделение интенсивной терапии и разницу между простым и полным отображением случаев. Это может помочь:
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;
}
**
после параметров первого решения?
**
это опечатка, оставшаяся от попытки использовать жирный шрифт в синтаксисе кода.
toupper
вызывается с отрицательными числами.
Следующее работает для меня.
#include <algorithm>
void toUpperCase(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
int main()
{
std::string str = "hello";
toUpperCase(&str);
}
toupper
вызывается с отрицательными числами.
Используйте лямбду.
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);
Более быстрый, если вы используете только символы ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Обратите внимание, что этот код работает быстрее, но работает только в ASCII и не является «абстрактным» решением.
Если вам нужны решения UNICODE или более традиционные и абстрактные решения, найдите другие ответы и поработайте с методами строк C ++.
C++
, но вы написали C
ответ здесь. (Я не один из downvoters.)
'
?
Пока вы в порядке с ASCII-only и можете предоставить действительный указатель на память RW, в C есть простая и очень эффективная однострочная строка:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Это особенно хорошо для простых строк, таких как идентификаторы ASCII, которые вы хотите нормализовать в том же регистре символов. Затем вы можете использовать буфер для создания экземпляра std: string.
//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;
}
for (size_t i = 0 ...
. Там также нет веских причин, чтобы сделать его так трудно читать. Это также сначала копирует строку, а затем зацикливает ее. @ Ответ Люка лучше в некоторых отношениях, за исключением того, что он не использует 'a'
константы символов.
#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 (). И поиск локали обычно включает взятие блокировки.
Это также работает с C ++ 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());
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 );
reserve
и back_inserter
(чтобы строка копировалась только один раз). inline std::string to_lower(const std::string &s) { std::string result; result.reserve(s.size()); std::transform(s.begin(), s.end(), std::back_inserter( result ), static_cast<int(*)(int)>(std::tolower)); return result; }
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
*p = toupper(*p);
toupper
вызывается с отрицательными числами.
попробуйте toupper()
функцию ( #include <ctype.h>
). он принимает символы в качестве аргументов, строки состоят из символов, поэтому вам придется перебирать каждый отдельный символ, который при объединении составляет строку
toupper
вызывается с отрицательными числами. Вы должны были упомянуть необходимый актерский состав unsigned char
.
Вот последний код с C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
вызывается с отрицательными числами.
Ответ на @dirkgently очень вдохновляет, но я хочу подчеркнуть , что в связи с озабоченностью , как будет показано ниже,
Как и все другие функции из, поведение std :: toupper не определено, если значение аргумента не может быть представлено как unsigned char и равно EOF. Чтобы безопасно использовать эти функции с простыми символами (или знаковыми), сначала необходимо преобразовать аргумент в unsigned char.
Ссылка : std :: toupper
правильное использование std::toupper
должно быть:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string>
void ToUpper(std::string& input)
{
std::for_each(std::begin(input), std::end(input), [](char& c) {
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
});
}
int main()
{
std::string s{ "Hello world!" };
std::cout << s << std::endl;
::ToUpper(s);
std::cout << s << std::endl;
return 0;
}
Вывод:
Hello world!
HELLO WORLD!
не уверен, что есть встроенная функция. Попробуй это:
Включите библиотеки 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
}
toupper
вызывается с отрицательными числами.
Мое решение (очистка 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++;
}
}
toupper
вызывается с отрицательными числами.
Все эти решения на этой странице сложнее, чем они должны быть.
Сделай это
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
цикл.
помните, что размер строки тоже возвращает разделитель, поэтому используйте <, а не <= в тесте цикла.
вывод будет: некоторая строка, которую вы хотите преобразовать
tolower
циклов, и большинство из них используют стандартные имена переменных цикла, например i
, не странные forLoop
.
Без использования каких-либо библиотек:
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;
}
Если вас интересуют только 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.
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;
}
Эта функция 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;
}
Я использую это решение. Я знаю, что вы не должны изменять эту область данных ... но я думаю, что это в основном из-за ошибок переполнения буфера и пустых символов .... вещи в верхнем регистре не одинаковы.
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]);
}
}
I know you're not supposed to modify that data area
- какую область данных вы не должны изменять?
str[i] = toupper(str[i]);
отлично (ну, не идеально , но исправляет большинство вещей неправильно).
::toupper
, скорее всего, предполагается ASCII.