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

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


person Tony Stark    schedule 18.04.2010    source источник
comment
Вы просто имеете дело с ASCII только с буквами az?   -  person Mark Byers    schedule 18.04.2010
comment
ascii. как бы я это учитывал? будет ли приведенный ниже пример работать? что произойдет, если мой char будет '#', и на нем будет вызван tolower()?   -  person Tony Stark    schedule 18.04.2010
comment
Это будет работать. Я больше думал о том, содержит ли ваша строка такие вещи, как é или Ü.   -  person Mark Byers    schedule 18.04.2010
comment
Почему бы просто не использовать strlwr? strlwr((char*)str); Он просто просматривает строку и преобразует ее сам.   -  person Larry    schedule 02.03.2018
comment
@ Ларри Это нестандартно.   -  person mid    schedule 28.05.2018


Ответы (6)


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

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

#include <ctype.h>

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

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

for ( ; *p; ++p) *p = tolower(*p);
person Earlz    schedule 18.04.2010
comment
for ( ; *p; ++p) *p = tolower(*p); кажется более идиоматичным. - person jfs; 18.04.2010
comment
@Дж.Ф. ну вот. Зависит от того, хотят ли они, чтобы код выглядел пугающе или красиво :) (очень читаемый один лайнер, но выглядит пугающе) - person Earlz; 18.04.2010
comment
это дает мне segfault, если str является char *, но не если str является массивом символов. Есть какое-нибудь объяснение этому? - person Electric Coffee; 23.11.2016
comment
@ElectricCoffee Я думаю, если вы использовали char *, вы действительно использовали строковую константу, которая помещается в недоступную для записи секцию памяти. Поэтому, если вы попытаетесь изменить это значение, это даст вам segfault. Если, с другой стороны, вы скопируете эту постоянную строку в char *copy = strdup (const_string), то copy можно будет изменить, поскольку она размещена в куче, доступной для записи. Так что в целом это не имеет ничего общего с использованием указателя (char *), а с использованием строк-констант, как в коде: char *const_str = "my const string". - person Jan; 05.09.2017
comment
Я считаю, что один лайнер заставит вас потерять указатель на строку. - person Ace.C; 08.09.2017
comment
Я считаю, что один лайнер будет иметь неисчислимые последствия. - person NOP da CALL; 25.03.2018
comment
однострочник приводит к error: lvalue required as increment operand - person nmz787; 26.04.2018
comment
@jfs Почему бы не while (*p = tolower(*p)) ++p; или while (*p = tolower(*p++)) для запутывания (последнее работает только с C++ 17) ;-) - person L. F.; 18.05.2019

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

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
person Oleg Razgulyaev    schedule 18.04.2010
comment
Чтобы сделать его немного более читабельным, вы можете сделать for(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p; - person Grant Peters; 18.04.2010
comment
Эта версия на самом деле медленнее, чем tolower() glibc. 55,2 против 44,15 на моей машине. - person jfs; 18.04.2010
comment
я не могу себе этого представить: tolower() работает с символами; только если макро - person Oleg Razgulyaev; 18.04.2010
comment
@oraz: tolower() имеет подпись int (*)(int). Вот код, используемый для измерения производительности gist.github.com/370497. - person jfs; 18.04.2010
comment
@JF: я вижу, они использовали таблицу, но я могу оптимизировать: for ( ; *p; ++p) if(*p › 'Z') {продолжить;} else if (*p ‹ 'A') {продолжить;} иначе {*p = *p|0x60;} - person Oleg Razgulyaev; 19.04.2010
comment
@oraz: оптимизация if (*p > 'Z') лучше работает с вводом, который я использовал, но если много заглавных букв, это занимает столько же времени, сколько и предыдущая версия. - person jfs; 19.04.2010
comment
Самая быстрая версия использует таблицу поиска вместо ветвей. - person Joe; 09.05.2020
comment
Обратите внимание, что это преобразование только для ASCII, которое строго не соответствует C. C не дает гарантий того, что буквы верхнего (или нижнего) регистра будут представлены последовательно в любом наборе символов. - person Andrew Henle; 03.07.2020

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

person Mark Byers    schedule 18.04.2010
comment
что произойдет, если tolower() вызывается для не-ascii a-z char? как '!' или '#'. я проверил его на «#», и, похоже, он работал нормально. это вообще верно для всех символов ascii, которые не являются буквами az? - person Tony Stark; 18.04.2010
comment
@hatorade: tolower() оставляет аргумент без изменений, если он не находится в диапазоне «A»... «Z». - person jfs; 18.04.2010
comment
! и # оба являются символами ascii. Марк имел в виду другие кодировки, такие как UTF8, где вы не можете предположить, что на каждый символ приходится один байт (как это делает это решение) - person hdgarrood; 23.11.2012

Если вам нужна поддержка Unicode в функции нижнего регистра, см. этот вопрос: Light C Unicode Library

person Eduardo    schedule 19.11.2010

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

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

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

person Ken S    schedule 22.05.2013
comment
Да, это будет складывать/веретено/искажать различные символы (в ASCII любой символ, управляющий символ или цифра с очищенным битом 5 станет тем же кодом символа с установленным битом 5 и т. д.), так что действительно, серьезно, не используй это. - person Ken S; 23.05.2013
comment
Этот пост обсуждается в мета. - person Patrick Hofman; 02.09.2014

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

#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;
}
person cscan    schedule 30.04.2020