Bagaimana cara menurunkan huruf kecil di C?

108

Bagaimana cara mengubah string kasus campuran menjadi string huruf kecil di C?

Tony Stark
sumber
2
Apakah Anda hanya berurusan dengan ASCII dengan huruf az saja?
Mark Byers
1
ascii. bagaimana saya memperhitungkannya? apakah contoh di bawah ini akan tetap berfungsi? apa yang terjadi jika karakter saya adalah '#' dan tolower () dipanggil?
Tony Stark
1
Itu akan bekerja. Saya lebih berpikir jika string Anda berisi hal-hal seperti é atau Ü.
Mark Byers
1
Mengapa tidak menggunakan "strlwr" saja? strlwr((char*)str);Itu hanya melewati string dan mengubahnya sendiri.
Larry
1
@ Larry Ini non-standar.
Pertengahan

Jawaban:

153

Ada di pustaka standar, dan itulah cara paling mudah yang dapat saya lihat untuk mengimplementasikan fungsi seperti itu. Jadi ya, cukup putar melalui string dan ubah setiap karakter menjadi huruf kecil.

Sesuatu yang sepele seperti ini:

#include <ctype.h>

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

atau jika Anda lebih suka satu liner, maka Anda dapat menggunakan yang ini dari JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
sumber
35
for ( ; *p; ++p) *p = tolower(*p);tampaknya lebih idiomatis.
jfs
14
@JF itu dia. Tergantung pada apakah mereka ingin kodenya terlihat menakutkan atau bagus :) (satu baris yang sangat mudah dibaca, tetapi memang terlihat menakutkan)
Earlz
ini memberi saya segfault jika str adalah a char *, tetapi tidak jika str adalah array char. Punya penjelasan untuk itu?
Kopi Elektrik
1
Saya percaya satu liner akan menyebabkan Anda kehilangan pointer Anda ke string.
Ace.C
2
Saya percaya bahwa satu liner akan memiliki konsekuensi yang tak terhitung.
NOP da CALL
7

untuk mengonversi ke huruf kecil sama dengan bit naik 0x60 jika Anda membatasi diri Anda pada ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Oleg Razgulyaev
sumber
6
Untuk membuatnya sedikit lebih mudah dibaca, Anda dapat melakukannyafor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Grant Peters
7
Versi ini sebenarnya lebih lambat dari versi glibc tolower(). 55.2 vs. 44.15 di komputer saya.
jfs
saya tidak bisa membayangkan bahwa: tolower () berurusan dengan karakter; hanya jika itu makro
Oleg Razgulyaev
1
@oraz: tolower () memiliki int (*)(int)tanda tangan. Berikut kode yang digunakan untuk pengukuran kinerja gist.github.com/370497
jfs
@JF: begitu, mereka telah menggunakan tabel, tetapi saya dapat mengoptimalkan: for (; * p; ++ p) if (* p> 'Z') {lanjutkan;} else if (* p <'A') {lanjutkan;} lain {* p = * p | 0x60;}
Oleg Razgulyaev
1

Apakah Anda hanya berurusan dengan string ASCII, dan tidak memiliki masalah lokal? Kalau begitu ya, itu cara yang bagus untuk melakukannya.

Mark Byers
sumber
apa yang terjadi jika tolower () dipanggil pada non-ascii az char? Suka '!' atau '#'. saya mengujinya di '#' dan tampaknya berfungsi dengan baik. apakah ini umumnya benar untuk semua karakter ascii yang bukan huruf az?
Tony Stark
1
@hatorade: tolower()membiarkan argumen tidak berubah jika tidak ada dalam kisaran 'A' .. 'Z'.
jfs
1
! dan # keduanya karakter ascii. Mark mengacu pada pengkodean lain seperti UTF8, di mana Anda tidak dapat berasumsi bahwa ada satu byte per karakter (seperti yang dilakukan solusi ini)
hdgarrood
1

Jika Anda memerlukan dukungan Unicode dalam fungsi huruf kecil, lihat pertanyaan ini: Light C Unicode Library

Eduardo
sumber
1

Jika kita akan menjadi ceroboh dalam menggunakan tolower(), lakukan ini:

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

Tapi, yah, itu agak meledak jika Anda memberinya beberapa simbol / angka, dan secara umum itu jahat. Pertanyaan wawancara yang bagus.

Ken S
sumber
6
Ya, ini akan melipat / spindle / memutilasi berbagai simbol (di ASCII, simbol apa pun, karakter kontrol, atau angka dengan bit 5 jelas akan menjadi kode karakter yang sama dengan set bit 5, dll) jadi sungguh, serius, jangan Gunakan.
Ken S
Posting ini dibahas di meta .
Patrick Hofman
0

Memutar ulang penunjuk untuk mendapatkan kinerja yang lebih baik:

#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
sumber