简体   繁体   English

您如何将字符数字转换为十进制并返回或将 ASCII 'A'-'Z'/'a'-'z' 转换为 'A'/'a' 的字母偏移量 0 ......?

[英]How do you convert char numbers to decimal and back or convert ASCII 'A'-'Z'/'a'-'z' to letter offsets 0 for 'A'/'a' ...?

If you have a char that is in the range '0' to '9' how do you convert it to int values of 0 to 9如果您有一个在“0”到“9”范围内的字符,您如何将其转换为 0 到 9 的 int 值

And then how do you convert it back?然后你如何将它转换回来?

Also given letters 'A' to 'Z' or 'a' to 'z' how do you convert them to the range 0-25 and then back?还给出了字母“A”到“Z”或“a”到“z”,你如何将它们转换到 0-25 的范围然后再返回?

It is okay to optimize for ASCII可以针对 ASCII 优化

The basic char encoding specified by C++ makes converting to and from '0' - '9' easy. C++ 指定的基本字符编码使得与“0”-“9”之间的转换变得容易。

C++ specifies: C++ 规定:

In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.在源和执行基本字符集中,上述十进制数字列表中 0 之后的每个字符的值都应比前面的值大 1。

This means that, whatever the integral value of '0', the integral value of '1' is '0' + 1 , the integral value of '2' is '0' + 2 , and so on.这意味着,无论 '0' 的整数值如何,'1' 的整数值是'0' + 1 ,'2' 的整数值是'0' + 2 ,依此类推。 Using this information and the basic rules of arithmetic you can convert from char to int and back easily:使用这些信息和算术的基本规则,您可以轻松地从 char 转换为 int 并返回:

char c = ...; // some value in the range '0' - '9'
int int_value = c - '0';

// int_value is in the range 0 - 9
char c2 = '0' + int_value;

Portably converting the letters 'a' to 'z' to numbers from 0 to 25 is not as easy because C++ does not specify that the values of these letters are consecutive.将字母 'a' 到 'z' 可移植地转换为从 0 到 25 的数字并不容易,因为 C++ 没有指定这些字母的值是连续的。 In ASCII they are consecutive, and you can write code that relies on that similar to the above code for '0' - '9'.在 ASCII 中,它们是连续的,您可以编写依赖于类似于上述 '0' - '9' 代码的代码。 (These days ASCII is used most everywhere). (如今,ASCII 在任何地方都被使用得最多)。

Portable code would instead use a lookup table or a specific checks for each character:可移植代码将改为使用查找表或对每个字符进行特定检查:

char int_to_char[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};

int char_to_int[CHAR_MAX + 1] = {};

for (int i=0; i<sizeof(int_to_char); ++i) {
  char_to_int[int_to_char[i]] = i;
}

// convert a lowercase char letter to a number in the range 0 - 25:
int i = char_to_int['d'];

// convert an int in the range 0 - 25 to a char
char c = int_to_char[25];

In C99 you can just directly initialize the char_to_int[] data without a loop.在 C99 中,您可以直接初始化char_to_int[]数据而无需循环。

int char_to_int[] = {['a'] = 0, ['b'] = 1, ['c'] = 2, ['d'] = 3, ['e'] = 4, ['f'] = 5, ['g'] = 6, ['h'] = 7, ['i'] = 8, ['j'] = 9, ['k'] = 10, ['l'] = 11, ['m'] = 12, ['n'] = 13, ['o'] = 14, ['p'] = 15, ['q'] = 16, ['r'] = 17, ['s'] = 18, ['t'] = 19, ['u'] = 20, ['v'] = 21, ['w'] = 22, ['x'] = 23, ['y'] = 24, ['z'] = 25};

C++ compilers that also support C99 may support this in C++ as well, as an extension.也支持 C99 的 C++ 编译器也可以在 C++ 中支持这一点,作为扩展。


Here's a complete program that generates random values to use in these conversions.这是一个完整的程序,可生成用于这些转换的随机值。 It uses C++, plus the C99 designated initialization extension.它使用 C++,加上 C99 指定的初始化扩展。

#include <cassert>

int digit_char_to_int(char c) {
  assert('0' <= c && c <= '9');
  return c - '0';
}

char int_to_digit_char(int i) {
  assert(0 <= i && i <= 9);
  return '0' + i;
}

int alpha_char_to_int(char c) {
  static constexpr int char_to_int[] = {['a'] = 0, ['b'] = 1, ['c'] = 2, ['d'] = 3, ['e'] = 4, ['f'] = 5, ['g'] = 6, ['h'] = 7, ['i'] = 8, ['j'] = 9, ['k'] = 10, ['l'] = 11, ['m'] = 12, ['n'] = 13, ['o'] = 14, ['p'] = 15, ['q'] = 16, ['r'] = 17, ['s'] = 18, ['t'] = 19, ['u'] = 20, ['v'] = 21, ['w'] = 22, ['x'] = 23, ['y'] = 24, ['z'] = 25};

  assert(0 <= c && c <= sizeof(char_to_int)/sizeof(*char_to_int));
  int i = char_to_int[c];
  assert(i != 0 || c == 'a');
  return i;
}

char int_to_alpha_char(int i) {
  static constexpr char int_to_char[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};

  assert(0 <= i && i <= 25);
  return int_to_char[i];
}

#include <random>
#include <iostream>

int main() {
  std::random_device r;
  std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
  std::mt19937 m(seed);

  std::uniform_int_distribution<int> digits{0, 9};
  std::uniform_int_distribution<int> letters{0, 25};

  for (int i=0; i<20; ++i) {
    int a = digits(m);
    char b = int_to_digit_char(a);
    int c = digit_char_to_int(b);

    std::cout << a << " -> '" << b << "' -> " << c << '\n';
  }

  for (int i=0; i<20; ++i) {
    int a = letters(m);
    char b = int_to_alpha_char(a);
    int c = alpha_char_to_int(b);

    std::cout << a << " -> '" << b << "' -> " << c << '\n';
  }

}

There are two main ways to do this conversion: Lookup and Mathmatically有两种主要方法可以进行这种转换:查找数学

All ASCII values are denoted in decimal notion in this answer在此答案中,所有 ASCII 值都以十进制表示

Note that in ASCII: '0' is 48 , 'A' is 65 , and 'a' is 97请注意,在 ASCII 中: '0' is 48'A' is 65 ,而'a' is 97

Lookup:抬头:

In the lookup version you have an array of char , and then place the mapped values in the array, and create an array of ints to convert back:在查找版本中,您有一个char数组,然后将映射的值放入该数组中,并创建一个 int 数组以转换回来:

In order to both validate and get the corresponding value when mapping char to int :为了在将char映射到int时验证并获取相应的值:

0 will be a sentinal value to mean not mapped: out of range    
all results will be one more than expected

unsigned char is used to make sure a signed negative char is handled correctly unsigned char用于确保正确处理有符号负字符

While 'C' allows the notation { ['A'] = 1, ['B'] = 2,… };而 'C' 允许符号 { ['A'] = 1, ['B'] = 2,... }; , C++ does not, so generically the following code can be used to fill lookup tables: , C++ 没有,所以一般可以使用以下代码来填充查找表:

void fill_lookups(unsigned char * from_table, int from_size, int * to_table)
{
     for (int i = 0; i < from_size; ++i)
     {
         to_table[from_table[i]]=i+1; // add one to support 0 as "out of range"
     }
}

unsigned char int_to_char[]={ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
unsigned char int_to_lower[]={'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
                     'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
                     'u', 'v', 'w', 'x', 'y', 'z'};
unsigned char int_to_upper[]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
                     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
                     'U', 'V', 'W', 'X', 'Y', 'Z'};

int char_to_int[UCHAR_MAX+2] = {};       // This will return 0 for non digits
int letter_to_offset[UCHAR_MAX+2] = {};  // This will return 0 for non alpha

fill_lookups(int_to_char, sizeof(int_to_char), char_to_int);
fill_lookups(int_to_lower, sizeof(int_to_lower), letter_to_offset);
fill_lookups(int_to_upper, sizeof(int_to_upper), letter_to_offset);

// Helper function to check in range and always reduce in range lookups by 1
int to_int(int * table, unsigned char c, bool * in_range)
{
   int ret = table[c];
   if (ret)
   {
       *in_range=(1==1); // for C/C++ true
       --ret;
   }
   else
   {
       *in_range=(0==1); // for C/C++ false
   }

   return ret;
}

bool in_range;  // always true in these cases
int a=to_int(char_to_int, '7', &in_range); // a is now 7
char b=int_to_char[7]; // b is now '7'    
int c=to_int(letter_to_offset, 'C', &in_range); // c=2
int d=to_int(letter_to_offset, 'c', &in_range); // d=2
char e=int_to_upper[2]; // e='C'
char f=int_to_lower[2]; // f='c'

While this will work and if validation or other lookups are needed this might make sense, but...虽然这会起作用,并且如果需要验证或其他查找,这可能是有道理的,但是......

In general a better way to do this is using mathmatic equations .一般来说,更好的方法是使用数学方程

Mathmatically (alpha works for ASCII)数学上(alpha 适用于 ASCII)

Assuming that the conversions have already been validated to be in the correct range: (C style cast used for use with C or C++)假设转换已经被验证在正确的范围内:(用于 C 或 C++ 的 C 样式转换

Note that '0'-'9' are guarenteed to be consecutive in C and C++请注意,'0'-'9' 保证在 C 和 C++ 中是连续的

For ASCII 'AZ' and 'az' are not only consecutive but 'A' % 32 and 'a' % 32 are both 1对于 ASCII 'AZ' 和 'az' 不仅是连续的而且'A' % 32'a' % 32都是 1

int a='7'-'0';         // a is now 7 in ASCII: 55-48=7

char b=(char)7+'0';    // b is now '7' in ASCII: 7 + 48

int c='C' % 32 - 1;    // c is now 2 in ASCII : 67 % 32 = 3 - 1 = 2

-or- where we know it is uppercase - 或 -我们知道它是大写的

int c='C'-'A';         // c is now 2 in ASCII : 67 - 65 = 2


int d='c' % 32 - 1;    // d is now 2 in ASCII : 99 % 32 = 3 - 1 = 2

-or- where we know it is lowercase - 或 -我们知道它是小写的

int d='c'-'a';         // d is now 2 in ASCII : 99 - 97 = 2

char e=(char)2 + 'A';  // e is 'C' in ASCII : 65 + 2 = 67
char f=(char)2 + 'a';  // f is 'c' in ASCII : 97 + 2 = 99

If you know a character c is either a letter or number, you can just do:如果您知道字符c是字母或数字,您可以这样做:

int cton( char c )
{
  if( 'a' <= c ) return c-'a';
  if( 'A' <= c ) return c-'A';
  return c-'0';
}

Add whatever error checking on c is needed.添加任何需要的c错误检查。

To convert an integer n back to a char , just do '0'+n if you want a digit, 'A'+n if you want an uppercase letter, and 'a'+n if you want lowercase.要将整数n转换回char ,如果需要数字,只需执行'0'+n ,如果需要大写字母,请执行'A'+n如果需要小写字母,只需执行'a'+n

Note: This works for ASCII (as the OP is tagged.) See Pete's informative comment however.注意:这适用于 ASCII(因为 OP 被标记。)但是请参阅 Pete 的信息性评论。

If I understand correctly, you want to do this:如果我理解正确,你想这样做:

#include <ctype.h>    /* for toupper */

int digit_from_char(char c) {
    return c - '0';
}

char char_from_digit(int d) {
    return d + '0';
}

int letter_from_char(char c) {
    return toupper(c) - 'A';
}

char char_from_letter(int l) {
    return l + 'A';
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM