Как сделать строчную строку на C?

108

Как преобразовать строку со смешанным регистром в строку в нижнем регистре на C?

Тони Старк
источник
2
Вы имеете дело с ASCII только с буквами az?
Марк Байерс
1
ascii. как бы это учесть? будет ли приведенный ниже пример работать? что произойдет, если мой char - это '#' и на нем будет вызвана функция tolower ()?
Тони Старк
1
Это будет работать. Я больше думал, содержит ли ваша строка такие вещи, как é или Ü.
Марк Байерс
1
Почему бы просто не использовать "strlwr"? strlwr((char*)str);Он просто перебирает строку и сам ее преобразует.
Ларри
1
@Larry Это нестандартно.
середина

Ответы:

153

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

Что-то вроде этого банального:

#include <ctype.h>

for(int i = 0; str[i]; i++){
  str[i] = tolower(str[i]);
}

или, если вы предпочитаете один лайнер, вы можете использовать этот от JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
источник
35
for ( ; *p; ++p) *p = tolower(*p);кажется более идиоматичным.
jfs
14
@JF вот и все. Зависит от того, хотят ли они, чтобы код выглядел страшно или красиво :) (один лайнер очень читабельный, но выглядит страшно)
Earlz
это дает мне segfault, если str является a char *, но не если str является массивом char. Есть какое-нибудь объяснение этому?
Electric Coffee
1
Я считаю, что один лайнер приведет к потере указателя на строку.
Ace.C 08
2
Я верю, что один лайнер будет иметь неописуемые последствия.
NOP da CALL
7

преобразование в нижний регистр эквивалентно увеличению бита 0x60, если вы ограничиваете себя ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Олег Разгуляев
источник
6
Чтобы сделать его более читабельным, вы могли бы сделатьfor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Грант Питерс
7
Эта версия на самом деле медленнее, чем у glibc tolower(). 55,2 против 44,15 на моей машине.
jfs
я не могу себе представить, что: tolower () имеет дело с символами; только если это макро
Олег Разгуляев
1
@oraz: у tolower () есть int (*)(int)подпись. Вот код, используемый для измерения производительности gist.github.com/370497
jfs
@JF: я вижу, они использовали таблицу, но я могу оптимизировать: for (; * p; ++ p) if (* p> 'Z') {continue;} else if (* p <'A') {continue;} else {* p = * p | 0x60;}
Олег Разгуляев
1

Вы имеете дело только со строками ASCII и не имеете проблем с локалью? Тогда да, это был бы хороший способ сделать это.

Марк Байерс
источник
что произойдет, если tolower () вызывается для не-ascii az char? лайк '!' или '#'. Я тестировал его на '#', и, похоже, он работал нормально. это вообще верно для всех символов ascii, которые не являются буквами az?
Тони Старк
1
@hatorade: tolower()оставляет аргумент без изменений, если он не находится в диапазоне 'A' ... 'Z'.
jfs
1
! и # оба являются символами ascii. Марк имел в виду другие кодировки, такие как UTF8, где вы не можете предположить, что на каждый символ приходится один байт (как это решение)
hdgarrood
1

Если мы собираемся быть настолько небрежными в использовании tolower(), сделайте следующее:

char blah[] = "blah blah Blah BLAH blAH\0"; int i=0; while(blah[i]|=' ', blah[++i]) {}

Но, ну, он вроде как взрывается, если вы кормите его некоторыми символами / цифрами, и в целом это зло. Тем не менее, хороший вопрос для собеседования.

Ken S
источник
6
Да, это будет сворачивать / раскручивать / искажать различные символы (в ASCII любой символ, управляющий символ или цифра с чистым битом 5 станет одним и тем же кодом символа с установленным битом 5 и т. Д.), Так что действительно, серьезно, не используй это.
Ken S
Этот пост обсуждается на мета .
Патрик Хофман
1

Зацикливание указателя для повышения производительности:

#include <ctype.h>

char* toLower(char* s) {
  for(char *p=s; *p; p++) *p=tolower(*p);
  return s;
}
char* toUpper(char* s) {
  for(char *p=s; *p; p++) *p=toupper(*p);
  return s;
}
cscan
источник