При сравнении без учета регистра более эффективно преобразовать строку в верхний или нижний регистр? Это вообще имеет значение?
В этом сообщении SO предлагается, что C # более эффективен с ToUpper, потому что «Microsoft оптимизировала его таким образом». Но я также читал этот аргумент, что преобразование ToLower и ToUpper зависит от того, что ваши строки содержат больше, и что обычно строки содержат больше символов нижнего регистра, что делает ToLower более эффективным.
В частности, хотелось бы знать:
- Есть ли способ оптимизировать ToUpper или ToLower таким образом, чтобы один был быстрее другого?
- Быстрее ли проводить сравнение строк в верхнем или нижнем регистре без учета регистра и почему?
- Существуют ли какие-либо среды программирования (например, C, C #, Python и т. Д.), В которых один случай явно лучше другого, и почему?
источник
От Microsoft в MSDN:
Почему? От Microsoft :
Каков пример такого персонажа, который не может совершить путешествие туда и обратно?
.NET Fiddle
Вот почему, если вы хотите проводить сравнения без учета регистра, вы конвертируете строки в верхний регистр, а не в нижний.
Поэтому, если вам нужно выбрать один, выберите Прописные буквы .
источник
ToUpper()
она во многих системах превратится в «SS». Так что на самом деле это тоже невозможно.ToUpperInvariant()
, поэтому было бы неплохо увидеть реальные примеры, почему верхний регистр лучше строчногоСогласно MSDN, более эффективно передавать строки и указывать при сравнении игнорировать регистр:
Конечно, если вы снова и снова сравниваете одну строку, это может не выполняться.
источник
Основываясь на том, что строки имеют больше записей в нижнем регистре, ToLower теоретически должен быть быстрее (много сравнений, но мало присваиваний).
В C или при использовании индивидуально доступных элементов каждой строки (таких как строки C или строковый тип STL в C ++) на самом деле это сравнение байтов, поэтому сравнение
UPPER
ничем не отличается отlower
.Если бы вы были хитрыми и
long
вместо этого загрузили свои строки в массивы, вы бы получили очень быстрое сравнение всей строки, потому что оно могло бы сравнивать 4 байта за раз. Однако время загрузки может сделать это нецелесообразным.Зачем нужно знать, что быстрее? Если вы не выполняете метрическую контрольную нагрузку сравнений, одно, выполняемое на пару циклов быстрее, не имеет отношения к скорости общего выполнения и звучит как преждевременная оптимизация :)
источник
s
иt
в массивы long, такие, что строки равны, если массивы равны, вам нужно пройти вниз s и t, пока не найдете завершающий'\0'
символ (или вы можете сравнить мусор за концом строк, что может быть незаконным доступом к памяти, вызывающим неопределенное поведение). Но тогда почему бы просто не провести сравнения, проходя по персонажам одного за другим? С помощью строк C ++ вы, вероятно, можете получить длину и.c_str()
, привести кlong *
и сравнить префикс длины.size() - .size()%(sizeof long)
. Мне кажется, это немного подозрительно.long
s только для сравнения было бы глупо. Но если вы делаете это «много» - я мог бы увидеть возможный аргумент в пользу того, чтобы это было сделано.Microsoft оптимизировала
ToUpperInvariant()
, нетToUpper()
. Разница в том, что инвариант более дружелюбен к культуре. Если вам нужно выполнить сравнение без учета регистра для строк, которые могут отличаться по культуре, используйте Invariant, иначе производительность инвариантного преобразования не имеет значения.Я не могу сказать, что быстрее - ToUpper () или ToLower (). Я никогда не пробовал это, поскольку у меня никогда не было ситуации, когда производительность имела такое большое значение.
источник
Если вы выполняете сравнение строк в C #, значительно быстрее использовать .Equals () вместо преобразования обеих строк в верхний или нижний регистр. Еще один большой плюс использования .Equals () заключается в том, что больше памяти не выделяется для двух новых строк верхнего / нижнего регистра.
источник
Это действительно не должно иметь никакого значения. С символами ASCII это определенно не имеет значения - это всего лишь несколько сравнений и небольшое изменение в любом направлении. Unicode может быть немного сложнее, поскольку есть некоторые символы, которые странным образом меняют регистр, но на самом деле не должно быть никакой разницы, если ваш текст не заполнен этими специальными символами.
источник
При правильном выполнении должно быть небольшое, незначительное преимущество в скорости, если вы конвертируете в нижний регистр, но это, как многие намекали, зависит от культуры и наследуется не в функции, а в строках, которые вы конвертируете (много строчных букв означает несколько присвоений памяти) - преобразование в верхний регистр происходит быстрее, если у вас есть строка с большим количеством заглавных букв.
источник
Мне нужны были фактические данные об этом, поэтому я вытащил полный список двухбайтовых символов, которые не работают с
ToLower
илиToUpper
. Затем я провел этот тест ниже:using System; class Program { static void Main() { char[][] pairs = { new[]{'\u00E5','\u212B'},new[]{'\u00C5','\u212B'},new[]{'\u0399','\u1FBE'}, new[]{'\u03B9','\u1FBE'},new[]{'\u03B2','\u03D0'},new[]{'\u03B5','\u03F5'}, new[]{'\u03B8','\u03D1'},new[]{'\u03B8','\u03F4'},new[]{'\u03D1','\u03F4'}, new[]{'\u03B9','\u1FBE'},new[]{'\u0345','\u03B9'},new[]{'\u0345','\u1FBE'}, new[]{'\u03BA','\u03F0'},new[]{'\u00B5','\u03BC'},new[]{'\u03C0','\u03D6'}, new[]{'\u03C1','\u03F1'},new[]{'\u03C2','\u03C3'},new[]{'\u03C6','\u03D5'}, new[]{'\u03C9','\u2126'},new[]{'\u0392','\u03D0'},new[]{'\u0395','\u03F5'}, new[]{'\u03D1','\u03F4'},new[]{'\u0398','\u03D1'},new[]{'\u0398','\u03F4'}, new[]{'\u0345','\u1FBE'},new[]{'\u0345','\u0399'},new[]{'\u0399','\u1FBE'}, new[]{'\u039A','\u03F0'},new[]{'\u00B5','\u039C'},new[]{'\u03A0','\u03D6'}, new[]{'\u03A1','\u03F1'},new[]{'\u03A3','\u03C2'},new[]{'\u03A6','\u03D5'}, new[]{'\u03A9','\u2126'},new[]{'\u0398','\u03F4'},new[]{'\u03B8','\u03F4'}, new[]{'\u03B8','\u03D1'},new[]{'\u0398','\u03D1'},new[]{'\u0432','\u1C80'}, new[]{'\u0434','\u1C81'},new[]{'\u043E','\u1C82'},new[]{'\u0441','\u1C83'}, new[]{'\u0442','\u1C84'},new[]{'\u0442','\u1C85'},new[]{'\u1C84','\u1C85'}, new[]{'\u044A','\u1C86'},new[]{'\u0412','\u1C80'},new[]{'\u0414','\u1C81'}, new[]{'\u041E','\u1C82'},new[]{'\u0421','\u1C83'},new[]{'\u1C84','\u1C85'}, new[]{'\u0422','\u1C84'},new[]{'\u0422','\u1C85'},new[]{'\u042A','\u1C86'}, new[]{'\u0463','\u1C87'},new[]{'\u0462','\u1C87'} }; int upper = 0, lower = 0; foreach (char[] pair in pairs) { Console.Write( "U+{0:X4} U+{1:X4} pass: ", Convert.ToInt32(pair[0]), Convert.ToInt32(pair[1]) ); if (Char.ToUpper(pair[0]) == Char.ToUpper(pair[1])) { Console.Write("ToUpper "); upper++; } else { Console.Write(" "); } if (Char.ToLower(pair[0]) == Char.ToLower(pair[1])) { Console.Write("ToLower"); lower++; } Console.WriteLine(); } Console.WriteLine("upper pass: {0}, lower pass: {1}", upper, lower); } }
Результат ниже. Обратите внимание, что я также тестировал эти
Invariant
версии, и результат был точно таким же. Интересно, что одна из пар не справляется с обоими. Но исходя из этого ToUpper - лучший вариант .источник