Jak zrobić małe litery w ciągu w C?

108

Jak mogę przekonwertować ciąg mieszanych wielkości liter na ciąg małych liter w C?

Tony Stark
źródło
2
Czy masz do czynienia tylko z ASCII tylko z literami az?
Mark Byers
1
ascii. jak mam to wziąć pod uwagę? czy poniższy przykład nadal będzie działał? co się stanie, jeśli mój znak to „#” i zostanie wywołana funkcja tolower ()?
Tony Stark
1
To zadziała. Bardziej zastanawiałem się, czy twój ciąg zawiera rzeczy takie jak é lub Ü.
Mark Byers
1
Dlaczego po prostu nie użyć „strlwr”? strlwr((char*)str);Po prostu przechodzi przez ciąg i sam go przekształca.
Larry
1
@Larry To niestandardowe.
połowa

Odpowiedzi:

153

Znajduje się w bibliotece standardowej i jest to najprostszy sposób, w jaki widzę, aby zaimplementować taką funkcję. Więc tak, po prostu przejrzyj ciąg i zamień każdy znak na małe litery.

Coś tak trywialnego:

#include <ctype.h>

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

lub jeśli wolisz jedną wkładkę, możesz użyć tej od JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
źródło
35
for ( ; *p; ++p) *p = tolower(*p);wydaje się bardziej idiomatyczny.
jfs
14
@JF, proszę bardzo. Zależy od tego, czy chcą, aby kod wyglądał strasznie, czy ładnie :) (bardzo czytelny jeden liniowiec, ale wygląda przerażająco)
Earlz
to daje mi segfault, jeśli str jest a char *, ale nie, jeśli str jest tablicą char. Masz na to jakieś wyjaśnienie?
Kawa elektryczna
1
Wierzę, że jedna wkładka spowoduje, że stracisz wskazówkę na sznurku.
Ace.C
2
Wierzę, że jeden liniowiec będzie miał niezliczone konsekwencje.
NOP da CALL
7

konwersja na małe litery jest równoważna podniesieniu bitu 0x60, jeśli ograniczysz się do ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Oleg Razgulyaev
źródło
6
Aby uczynić go nieco bardziej czytelnym, możesz to zrobićfor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Grant Peters
7
Ta wersja jest w rzeczywistości wolniejsza niż glibc tolower(). 55,2 w porównaniu z 44,15 na moim komputerze.
jfs
nie wyobrażam sobie, że: tolower () zajmuje się znakami; tylko jeśli to makro
Oleg Razgulyaev
1
@oraz: tolower () ma int (*)(int)podpis. Oto kod używany do pomiarów wydajności gist.github.com/370497
jfs
@JF: widzę, że używali tabeli, ale mogę zoptymalizować: for (; * p; ++ p) if (* p> 'Z') {kontynuuj;} else if (* p <'A') {kontynuuj;} else {* p = * p | 0x60;}
Oleg Razgulyaev
1

Czy masz do czynienia tylko z ciągami znaków ASCII i nie masz problemów z lokalizacją? Więc tak, to byłby dobry sposób na zrobienie tego.

Mark Byers
źródło
co się stanie, jeśli funkcja tolower () zostanie wywołana na znaku niebędącym ascii az? lubić '!' lub „#”. przetestowałem to na '#' i wydawało się, że działa dobrze. czy jest to generalnie prawdziwe dla wszystkich znaków ascii, które nie są literami az?
Tony Stark
1
@hatorade: tolower()pozostawia argument niezmieniony, jeśli nie znajduje się w zakresie „A” .. „Z”.
jfs
1
! i # są znakami ascii. Mark odnosił się do innych kodowań, takich jak UTF8, w których nie można założyć, że na znak przypada jeden bajt (tak jak to rozwiązanie)
hdgarrood
1

Jeśli potrzebujesz obsługi Unicode w funkcji małych liter, zobacz to pytanie: Light C Unicode Library

Eduardo
źródło
1

Jeśli mamy być tak niechlujni, jak używać tolower(), zrób to:

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

Ale cóż, trochę eksploduje, jeśli nakarmisz go jakimiś symbolami / cyframi i ogólnie jest to zło. Dobre pytanie do wywiadu.

Ken S.
źródło
6
Tak, spowoduje to złożenie / wrzeciona / okaleczenie różnych symboli (w ASCII każdy symbol, znak kontrolny lub cyfra z wyczyszczonym bitem 5 stanie się tym samym kodem znaku z ustawionym bitem 5 itp.), Więc naprawdę, poważnie, nie rób tego Użyj tego.
Ken S
Ten post jest omawiany na meta .
Patrick Hofman
0

Zapętlenie wskaźnika w celu uzyskania lepszej wydajności:

#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
źródło