谢谢!
这是一种我认为比switch
方法更好的方式,而且符合标准(不假设ASCII):
#include <string.h>
#include <ctype.h>
/* returns -1 if c is not an alphabetic character */
int c_to_n(char c)
{
int n = -1;
static const char * const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr(alphabet, toupper((unsigned char)c));
if (p)
{
n = p - alphabet;
}
return n;
}
p - alphabet
进行强制转换。您可以使用 ptrdiff_t
或其他一些技术上正确的类型,但考虑到范围限制,我认为这并不是真正必要的。任何整数类型都保证能够容纳我们在此处使用的任何值。 - Chris Lutzp - alphabet
在0到25范围内,因此它一定适合于int
。我不认为需要进行强制转换 - 将一个整数类型赋值给另一个的语义是非常明确的。 - cafC标准并不保证字母的编码顺序是连续的。因此,可移植代码不能假设,例如'B'-'A'
等于1。
C规范的相关部分是5.2.1节,描述了字符集:
3 基本源和基本执行字符集都必须包含以下成员:拉丁字母的26个大写字母
ABCDEFGHIJKLM
NOPQRSTUVWXYZ
拉丁字母表中的26个小写字母
abcdefghijklm
nopqrstuvwxyz
这是10个十进制的数字
0123456789
下面的29个图形字符
!"#%&'()*+,-./:
;<=>?[\]^_{|}~
规范只保证数字具有顺序编码,对于字母字符的编码没有任何限制。
幸运的是,有一种简单高效的方法将A转换为0,B转换为1等。以下是代码:
char letter = 'E'; // could be any upper or lower case letter
char str[2] = { letter }; // make a string out of the letter
int num = strtol( str, NULL, 36 ) - 10; // convert the letter to a number
这个方法可行的原因可以在strtol
的手册页面中找到:
(在十进制以上的进制中,大写或小写字母'A'表示10,'B'代表11等等,'Z'代表35。)
因此,将36作为进制参数传递给strtol
函数告诉它将'A'
或 'a'
转换为 10,'B'
或 'b'
转换为 11,以此类推。只需要减去 10 就可以得到最终答案了。
如果你需要处理大小写,那么可以尝试以下操作:
if (letter >= 'A' && letter <= 'Z')
num = letter - 'A';
else if (letter >= 'a' && letter <= 'z')
num = letter - 'a';
如果您想要显示这些数字,那么您需要通过将数字加上字符 '0' 来转换成 ASCII 值:
asciinumber = num + '0';
num = toupper(letter) - 'A'
来将字母转换为大写形式,从而避免条件判断。toupper()
函数位于ctype.h
头文件中。 - Chris Lutz0x20
的差异。 - Noon Silk另一个比26个if
语句更糟糕(但仍比较好)的替代方案是使用switch
/case
:
switch(letter)
{
case 'A':
case 'a': // don't use this line if you want only capital letters
num = 0;
break;
case 'B':
case 'b': // same as above about 'a'
num = 1;
break;
/* and so on and so on */
default:
fprintf(stderr, "WTF?\n");
}
只有在字母和其代码之间绝对没有关系时才考虑使用此方法。由于在您的情况下,字母和代码之间存在明显的顺序关系,因此使用此方法相当愚蠢且难以维护。但是,如果您必须将随机字符编码为随机值,则这是避免编写大量 if()
/else if()
/else if()
/else
语句的方法。
有一种更好的方法。
在ASCII(www.asciitable.com)中,您可以了解这些字符的数字值。
'A'是0x41。
因此,您可以简单地从它们中减去0x41,以获得数字。我不太了解C语言,但是大概是这样:
int num = 'A' - 0x41;
int num = letter - 'A';
的意思是将字母转化为数字,其中'A'代表数字0,'B'代表1,以此类推。 - Nick Dandoulakisint num = 'A' - 'A'
(将第一个替换为所讨论的字符或变量)以防万一我们不使用ASCII,尽管我认为标准可能已经保证了这一点。我知道标准保证了'A'..'Z'在字符集中是连续的。 - Chris Lutz0x41
代替'A'
是愚蠢的。我们为什么不直接用二进制来写数字和字符串呢?为什么不计算自己的跳转和指针算术呢?@caf - 这个问题在各个地方都有提到,但是我今天心情比较糟糕,所以提醒一下也无妨。 ; ) 但是没错,我从连续的“0”-“9”推断出了“A”-“Z”,虽然并非如此,但除非你打算编写针对大型计算机的代码,否则这是一个相当安全的假设。这并不能改变事实,即在几乎所有情况下,“- 'A'”要比“- 0x41”更好。 - Chris Lutzfor ch in somestring:
if lowercase(ch):
n = ord(ch) - ord ('a')
elif uppercase(ch):
n = ord(ch) - ord('A')
else:
n = -1 # Sentinel error value
# (or raise an exception as appropriate to your programming
# environment and to the assignment specification)
当然,这种方法对于基于EBCDIC的系统可能不起作用(对于一些其他奇异字符集也可能不起作用)。我想一个合理的检查方法是测试该函数是否返回范围在0..26之间的单调递增值,对于字符串“abc...xzy”和“ABC...XYZ”。
另一种完全不同的方法是创建一个字母及其值的关联数组(字典、表、哈希)(一个或两个简单循环)。然后使用它。(大多数现代编程语言都包括对关联数组的支持。
当然,我不会“替你做功课”。你必须自己完成。我只是解释了那些显而易见的方法,任何专业程序员都会使用。(好吧,汇编语言黑客也可以每个字节掩码一个位)。
#include<stdio.h>
#include<ctype.h>
int val(char a);
int main()
{
char r;
scanf("%c",&r);
printf("\n%d\n",val(r));
}
int val(char a)
{
int i=0;
char k;
for(k='A';k<=toupper(a);k++)
i++;
return i;
}//enter code here
由于在C和C++中,char数据类型与int数据类型类似,因此您可以选择像这样的一些内容:
char c = 'A'; // just some character
int urValue = c - 65;
如果您担心大小写敏感性:
#include <ctype.h> // if using C++ #include <cctype>
int urValue = toupper(c) - 65;
唉,如果你有C++的话
对于Unicode,如何将字符映射到值的定义
typedef std::map<wchar_t, int> WCharValueMap;
WCharValueMap myConversion = fillMap();
WCharValueMap fillMap() {
WCharValueMap result;
result[L'A']=0;
result[L'Â']=0;
result[L'B']=1;
result[L'C']=2;
return result;
}
用法
int value = myConversion[L'Â'];
int ctoi(char c)
{
int index;
char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
c = toupper(c);
// avoid doing strlen here to juice some efficiency.
for(index = 0; index != 26; index++)
{
if(c == alphabet[index])
{
return index;
}
}
return -1;
}
strchr()
将那段代码简化为几行 :-) - paxdiablo