У меня есть строка (char *), и мне нужно найти ее базовый тип данных, такой как int, float, double, short, long или просто массив символов, содержащий алфавиты с цифрами или без них (например, varchar в SQL). Например:
char* str1 = "12312"
char* str2 = "231.342"
char* str3 = "234234243234"
char* str4 = "4323434.2432342"
char* str5 = "i contain only alphabets"
Учитывая эти строки, мне нужно найти, что первая строка имеет тип int, и привести ее к типу int, и т. д. пример:
int no1 = atoi(str1)
float no2 = atof(str2)
long no3 = atol(str3)
double no4 = strtod(str4)
char* varchar1 = strdup(str5)
Уточняю еще немного ...
У меня есть строка, и ее содержимое может быть алфавитом и / или цифрами и / или специальными символами. Прямо сейчас я могу разбирать строку и





Сначала проверьте, не решена ли проблема за вас. Возможно, ваши библиотечные функции для преобразования строк в числа уже выполняют необходимые вам проверки.
В противном случае вам нужно будет выполнить некоторое сопоставление с образцом в строках, и для этого нужны регулярные выражения!
Например. если строка соответствует регулярному выражению:
[+-]?\d+
тогда вы знаете, что это int или long. Преобразуйте его в длинный, а затем проверьте его размер. Если ваш long может уместиться в int, преобразуйте его в int.
Вы можете сделать то же самое для чисел с плавающей запятой и удвоения, хотя регулярное выражение немного сложнее.
Остерегайтесь неудобных случаев, таких как пустая строка, одинокая десятичная точка, слишком большие числа и так далее. Вам также необходимо решить, разрешите ли вы использовать экспоненциальную нотацию.
Попробуйте ввести его в длинный список с помощью sscanf. Если это не поможет, попробуйте превратить его в дубль с помощью sscanf. Если это не удается, это строка. Вы можете использовать преобразование% n, чтобы определить, весь ли ввод был успешно использован. Константы в <limits.h> и <float.h> могут помочь вам решить, подходят ли числовые результаты к более узким типам на вашей платформе. Если это не домашнее задание, возможно, ваши типы назначения определены извне - например, схемой базы данных - и последний комментарий не имеет значения.
sscanf () с использованием "% ld" с радостью преобразует ноль в "0.1234E-39" в целое число, так что это не очень помогает. Он также не сможет преобразовать 0xABCD без помощи в форме «0x% ld» в строке формата сканирования. И т.п.
1-й пункт - вот почему я сказал использовать% n. 2-й пункт -% x с радостью конвертирует 0xABCD. Примеры OP не включают шестнадцатеричный ввод; если ему это нужно, ему, очевидно, потребуется дополнительный звонок (как со Стртулом и друзьями). Я не собираюсь публиковать полное решение домашнего задания.
Прежде всего, вы должны решить, каких представителей вы хотите узнать. Например, является ли 0xBAC0 коротким словом без знака, выраженным в шестнадцатеричном формате? То же самое для 010 (в восьмеричном) и 1E-2 (для 0,01).
После того, как вы определились с представлением, вы можете использовать регулярные выражения для определения общих форм. Например:
-?\d*.\d*([eE]?[+-]?\d*.\d*)? - это число с плавающей запятой (почти оно принимает странные вещи, такие как .e-., вы должны определить регулярное выражение, которое наиболее подходит для вас)-?\d+ - целое число0x[0-9A-Fa-f]+ - шестнадцатеричная константаи так далее. Если вы не используете библиотеку регулярных выражений, вам придется написать небольшой синтаксический анализатор для этих повторных выражений с нуля.
Теперь вы можете преобразовать его в максимально возможный тип (например, long long для целых чисел, double для плавающих указателей), а затем использовать значения в limits.h, чтобы увидеть, подходит ли значение для меньшего типа.
Например, если целое число меньше SHRT_MAX, можно считать, что это short.
Возможно, вам также придется принимать произвольные решения, например, 54321 может быть только unsigned short, а 12345 может быть signed short или unsigned short.
1E-2 обычно составляет 0,01, не так ли?
В C (не в C++) я бы использовал комбинацию значений strtod / strol и max из <limits.h> и <float.h>:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>
/* Now, we know the following values:
INT_MAX, INT_MIN, SHRT_MAX, SHRT_MIN, CHAR_MAX, CHAR_MIN, etc. */
typedef union tagMyUnion
{
char TChar_ ; short TShort_ ; long TLong_ ; double TDouble_ ;
} MyUnion ;
typedef enum tagMyEnum
{
TChar, TShort, TLong, TDouble, TNaN
} MyEnum ;
void whatIsTheValue(const char * string_, MyEnum * enum_, MyUnion * union_)
{
char * endptr ;
long lValue ;
double dValue ;
*enum_ = TNaN ;
/* integer value */
lValue = strtol(string_, &endptr, 10) ;
if (*endptr == 0) /* It is an integer value ! */
{
if ((lValue >= CHAR_MIN) && (lValue <= CHAR_MAX)) /* is it a char ? */
{
*enum_ = TChar ;
union_->TChar_ = (char) lValue ;
}
else if ((lValue >= SHRT_MIN) && (lValue <= SHRT_MAX)) /* is it a short ? */
{
*enum_ = TShort ;
union_->TShort_ = (short) lValue ;
}
else if ((lValue >= LONG_MIN) && (lValue <= LONG_MAX)) /* is it a long ? */
{
*enum_ = TLong ;
union_->TLong_ = (long) lValue ;
}
return ;
}
/* real value */
dValue = strtod(string_, &endptr) ;
if (*endptr == 0) /* It is an real value ! */
{
if ((dValue >= -DBL_MAX) && (dValue <= DBL_MAX)) /* is it a double ? */
{
*enum_ = TDouble ;
union_->TDouble_ = (double) dValue ;
}
return ;
}
return ;
}
void studyValue(const char * string_)
{
MyEnum enum_ ;
MyUnion union_ ;
whatIsTheValue(string_, &enum_, &union_) ;
switch(enum_)
{
case TChar : printf("It is a char : %li\n", (long) union_.TChar_) ; break ;
case TShort : printf("It is a short : %li\n", (long) union_.TShort_) ; break ;
case TLong : printf("It is a long : %li\n", (long) union_.TLong_) ; break ;
case TDouble : printf("It is a double : %f\n", (double) union_.TDouble_) ; break ;
case TNaN : printf("It is a not a number : %s\n", string_) ; break ;
default : printf("I really don't know : %s\n", string_) ; break ;
}
}
int main(int argc, char **argv)
{
studyValue("25") ;
studyValue("-25") ;
studyValue("30000") ;
studyValue("-30000") ;
studyValue("300000") ;
studyValue("-300000") ;
studyValue("25.5") ;
studyValue("-25.5") ;
studyValue("25555555.55555555") ;
studyValue("-25555555.55555555") ;
studyValue("Hello World") ;
studyValue("555-55-55") ;
return 0;
}
В результате получается следующее:
[25] is a char : 25
[-25] is a char : -25
[30000] is a short : 30000
[-30000] is a short : -30000
[300000] is a long : 300000
[-300000] is a long : -300000
[25.5] is a double : 25.500000
[-25.5] is a double : -25.500000
[25555555.55555555] is a double : 25555555.555556
[-25555555.55555555] is a double : -25555555.555556
[Hello World] is a not a number
[555-55-55] is a not a number
Извините за мою ржавую C.
:-)
Итак, по сути, вы после вызова whatIsTheValue извлекаете тип через перечисление MyEnum, а затем, в соответствии со значением в этом перечислении, извлекаете правильное значение, правильно набранное из объединения MyUnion.
Обратите внимание, что определение того, является ли число двойным или плавающим, немного сложнее, потому что разница, похоже, заключается в точности, то есть представляет ли ваше число в двойном или в плавающем. А большинство «десятичных вещественных» чисел не совсем представимо в двойное, я бы не стал заморачиваться.
Также обратите внимание, что здесь есть загвоздка, поскольку 25.0 может быть как действительным, так и целым числом. Сравнивая "dValue == (double) (long) dValue", я думаю, вы должны знать, является ли это целым числом, опять же, не принимая во внимание обычные проблемы точности, возникающие с двоичными действительными числами, используемыми компьютерами.
Для каких значений long lValue тест (lValue> = LONG_MIN) && (lValue <= LONG_MAX) завершится ошибкой?
Пример не должен быть полным: он просто предлагает правильный шаблон, объединяющий перечисление, объединение и функцию поиска типов. Пользователь должен адаптировать эти символы к своим потребностям, таким как поддерживаемые типы, как он будет обрабатывать двойное число, то есть целое число, шестнадцатеричное представление и т. д.
Чтобы уточнить, базовым типом данных char * является char. Вы можете анализировать содержимое строки только до нужного вам типа, но вам нужно знать об этом заранее.