使用位操作测试整数是否为大写ASCII字母

时间:2016-02-07 19:02:13

标签: c

对于赋值,我正在尝试在C中创建一些仅使用位操作来测试整数是否为ASCII大写字母的代码。该字母将由整数形式的ASCII代码给出,即0x41 <= ourint <= 0x5A。在做了一些研究之后,我了解到小写字母和大写字母之间的区别是单词二进制版本的第六位数字。大写字母为1,大写字母为0

我几乎拥有它,但我的代码无效。

到目前为止我所拥有的是

!(((x>>6)<<31) & 0)

它的作用是将代码移动到右边6以获得第六个数字作为第一个数字,然后向右移动31以使其全部为0或1然后是31 0。我必须这样做,如果它是大写的,它返回1,所以我使用感叹号。

编辑:我的新代码

!((~(((x & 32)>>5))<<31))>>31)

但现在我仍然坚持0x7fffffff

的测试问题

4 个答案:

答案 0 :(得分:5)

您可以通过检查其c位来测试ASCII字母0x20是否为大写,对于大写,它必须是0,对于小写,它必须是1

if (!(c & 0x20))
    printf("ASCII letter %c is uppercase\n", c);

但请注意,如果您还不知道c是一封信,则此测试不起作用。它会错误地匹配'@''[''\\'']''^''_'以及高位的整个字符范围设置为192到223,它们不是ASCII的一部分,而是有效的unsigned char值。

如果您希望单个测试验证c是否为大写ASCII字母,请尝试:

if ((unsigned)(c - 'A') <= (unsigned)('Z' - 'A'))
     printf("%c is an uppercase ASCII letter\n", c);

编辑:目前还不清楚你是什么意思我不允许使用if语句或任何类型的转换操作。我必须测试这个数字是否在两个数字之间,包括远远超出ASCII代码范围的数字,如果是,则返回1,否则为0

  • 如果您知道c是一封信,则!(c & 0x20)(((c >> 5) & 1) ^ 1)如果1为大写则为c,如果0c则为(c >= 'A' && c <= 'Z')
  • 如果c可以是任何整数值,只需编写常规比较!((c >> 5) ^ 2) & (0x07fffffeU >> (c & 31)),编译器就会产生比尝试危险的比特技巧更好的代码。

再次编辑

由于#include <stdio.h> #include <stdlib.h> static int uppertest(int c) { return !((c >> 5) ^ 2) & (0x07fffffeU >> (c & 31)); } int main(int argc, char *argv[]) { for (int i = 1; i < argc; i++) { int c = strtol(argv[i], NULL, 0); printf("uppertest(%d) -> %d\n", c, uppertest(c)); } return 0; } 可以是任何整数值,并且您只允许进行位操作,因此这是另一种解决方案:{{1}}。以下是测试此程序的程序:

{{1}}

答案 1 :(得分:1)

  

...查看字母是否为大写

简化: 我们假设范围[A-Z]和[a-z] char相差一个值,即2的幂。所以'B'-'b'等于'X'-'x'等等。

#define CASE_MASK ('A' ^ 'a')

// Is letter uppercase?
int is_letter_upper(int ch) {
   return (ch & CASE_MASK) == ('A' & CASE_MASK);
}

// Is letter lowercase?
int is_letter_lower(int ch) {
   return (ch & CASE_MASK) == ('a' & CASE_MASK);
}

适用于ASCIIEBCIDIC

更多&#34;位操作&#34;答案

int is_letter_upperBM(int ch) {
   return !((ch & CASE_MASK) ^ ('A' & CASE_MASK));
}

答案 2 :(得分:0)

由于OP卡在案例0x7fffffff上,请通过扩展其他工作解决方案将其排除。

!((~(((x & 32)>>5))<<31))>>31) & !(x ^ 0x7fffffff)

迂腐地,只需编写如下代码,让编译器简化。

isupper = (!(x ^ 'A')) | (!(x ^ 'B')) | (!(x ^ 'C')) ... (!(x ^ 'Z'));

答案 3 :(得分:0)

如果允许,可以使用无符号整数除法:

!((x-0x41)/26)

但这可能不符合原始问题的精神。考虑当你从任何大写字母中减去0x3B时会发生什么:

A: 0x41 - 0x3B = 0x06
Z: 0x5A - 0x3B = 0x1F

这里有趣的特性是,任何最初大于0x5A的值都会设置一个高位(~0x1F)。您可以执行相同的移动来移动&#39; A&#39;降到零,所以最初小于&#39; A&#39;将设置高位。最后,一个解决方案只需要减法,一个或一些按位和:

!(((x-0x3B) & ~(0x1F)) || ((x-0x41) & ~(0x1F)))

我相信你做的就是你想要的。鉴于C中条件(短路)评估的性质,它有嵌入其中的隐式条件。如果你想删除它,最小化计算,并最大化你可以做到这一点的默默无闻:

!(((x-0x3B) | (x-0x41)) & ~(0x1F))

或我个人的新宠:

!((('Z'-x) | (x-'A')) & ~(0x1F))