Як можна перетворити рядок у верхній регістр. Приклади, які я знайшов у 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
підписано рівнину . (Причина: якщо це реалізовано як макрос, він, ймовірно, використовувати таблицю пошуку та ваші аргументи індексує цю таблицю. Від'ємний індекс дасть вам UB.)
Ця проблема піддається перебору SIMD для набору символів ASCII.
Попередній тест на x86-64 gcc 5.2 -O3 -march=native
на Core2Duo (Merom). Один і той же рядок з 120 символів (змішаний нижній і нижній регістр ASCII), перетворений у цикл 40 М разів (без перехресних файлів, тому компілятор не може оптимізувати або витягнути його з циклу). Буфери одних і тих же джерел і dest, тому жодних накладних ефектів або ефектів пам'яті / кешу немає, дані зберігаються в кеш-пам'яті 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
ввімкнув, і навіть однокроковим кроком засвідчив, що він робить. Це майже однакова швидкість з клангом ++ 3,8. Він має величезні накладні знаки всередині циклу. perf record
/ report
Результат (для 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 [.] 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 будуть автоматично векторизувати цикли лише тоді, коли перед циклом буде відомо число ітерацій. (тобто петлі пошуку, як звичайна реалізація на C strlen
, не автоматично визначають розмір.)
Таким чином, для рядків, досить малих, щоб вміститись у кеш, ми отримуємо значну швидкість для довгих ~ 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
(тому ми робимо копію), але вони не перетинаються (і не знаходяться поруч). Обидва вирівняні.
Деякі результати дещо відрізняються від кланг.
Цикл мікро-орієнтирів, який викликає функцію, знаходиться в окремому файлі. В іншому випадку він вставляється і strlen()
піднімається з петлі, і він працює різко швидше, особливо. для 16 рядків char (0,187s).
Це має головну перевагу в тому, що gcc може автоматично векторизувати його для будь-якої архітектури, але головним недоліком є те, що для звичайних звичайних випадків малих рядків це повільніше.
Отже, існують великі прискорення, але автоматична векторизація компілятора не робить великого коду, особливо. для очищення останніх до 15 символів.
На основі моєї функції обертання регістру, яка інвертує регістр кожного алфавітного символу. Скористається "підписом порівняння без підпису", де ви можете виконати 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
може перейти на наступну сторінку та розміститись за замовчуванням. Якщо нам потрібні будь-які байти у вирівняному фрагменті 16В, завжди безпечно завантажувати весь вирівняний шматок 16В.
Повне джерело: у суглобі github .
// 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 у деяких випадках, тому що я не хочу все час повторювати.)
Отже, для коротких рядків довше 16B це значно швидше, ніж автовекторизовані. Довжина шириною однієї, меншої за вектор не представляє проблеми. Вони можуть виникнути проблеми при роботі на місці через стійла переадресації магазину. (Але зауважте, що все-таки добре обробити власний вихід, а не оригінальний ввід, тому що таппер є ідентичним).
Існує багато можливостей для налаштування цього для різних випадків використання, залежно від того, що хоче оточуючий код, і цільової мікроархітектури. Отримати компілятор, щоб видати приємний код для частини очищення, складно. Використання 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 або International у рядках?
Якщо це останній випадок, "верхній регістр" не такий простий, і це залежить від використовуваного алфавіту. Існують двопалатні та однопалатні алфавіти. Тільки двопалатні алфавіти мають різні символи для верхнього та нижнього регістру. Також є складені символи, такі як латинська велика літера 'DZ' (\ u01F1 'DZ'), які використовують так званий регістр заголовка . Це означає, що змінюється лише перший символ (D).
Я пропоную вам розібратися в ICU та відмінність між простими та повнорозмірними відображеннями. Це може допомогти:
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
відповідь. (Я не один з низовидів.)
'
?
Поки ви добре працюєте лише з ASCII, і ви можете надати дійсний вказівник на 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, і, мабуть, те, що підсилюється :: to_upper робиться під ним.
Це тому, що :: toupper повинен шукати локаль - тому що він міг бути змінений іншим потоком - для кожного виклику, тоді як тут лише виклик до locale () має таке покарання. А пошук локалу зазвичай передбачає зняття блокування.
Це також працює з C ++ 98 після того, як ви заміните авто, використовуйте нову нестандартну str.data () та додайте пробіл для розбиття шаблону закриття (">>" to ">>") таким чином:
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 не визначена, якщо значення аргументу не є ні представним як неподписаний знак, ні рівне EOF. Щоб безпечно використовувати ці функції з простими символами (або з підписаними символами), аргумент спочатку слід перетворити на неподписаний 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.