Преобразование строки char в ее базовый тип данных

У меня есть строка (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)

Уточняю еще немного ...

У меня есть строка, и ее содержимое может быть алфавитом и / или цифрами и / или специальными символами. Прямо сейчас я могу разбирать строку и

  1. Определите, содержит ли он только цифры,
    Здесь я конвертирую строку в short, int или long, в зависимости от того, что лучше всего подходит. (Как узнать, можно ли преобразовать строку в короткое целое или длинное?)
  2. Только алфавиты, оставьте это в виде строки.
  3. Цифры с одной десятичной запятой.
    Здесь мне нужно преобразовать строку в float или double (Тот же вопрос здесь)
  4. Другие. оставь это как строку

Чтобы уточнить, базовым типом данных char * является char. Вы можете анализировать содержимое строки только до нужного вам типа, но вам нужно знать об этом заранее.

OregonGhost 12.10.2008 21:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
1 756
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Сначала проверьте, не решена ли проблема за вас. Возможно, ваши библиотечные функции для преобразования строк в числа уже выполняют необходимые вам проверки.

В противном случае вам нужно будет выполнить некоторое сопоставление с образцом в строках, и для этого нужны регулярные выражения!

Например. если строка соответствует регулярному выражению:

[+-]?\d+

тогда вы знаете, что это int или long. Преобразуйте его в длинный, а затем проверьте его размер. Если ваш long может уместиться в int, преобразуйте его в int.

Вы можете сделать то же самое для чисел с плавающей запятой и удвоения, хотя регулярное выражение немного сложнее.

Остерегайтесь неудобных случаев, таких как пустая строка, одинокая десятичная точка, слишком большие числа и так далее. Вам также необходимо решить, разрешите ли вы использовать экспоненциальную нотацию.

Попробуйте ввести его в длинный список с помощью sscanf. Если это не поможет, попробуйте превратить его в дубль с помощью sscanf. Если это не удается, это строка. Вы можете использовать преобразование% n, чтобы определить, весь ли ввод был успешно использован. Константы в <limits.h> и <float.h> могут помочь вам решить, подходят ли числовые результаты к более узким типам на вашей платформе. Если это не домашнее задание, возможно, ваши типы назначения определены извне - например, схемой базы данных - и последний комментарий не имеет значения.

sscanf () с использованием "% ld" с радостью преобразует ноль в "0.1234E-39" в целое число, так что это не очень помогает. Он также не сможет преобразовать 0xABCD без помощи в форме «0x% ld» в строке формата сканирования. И т.п.

Jonathan Leffler 13.10.2008 03:08

1-й пункт - вот почему я сказал использовать% n. 2-й пункт -% x с радостью конвертирует 0xABCD. Примеры OP не включают шестнадцатеричный ввод; если ему это нужно, ему, очевидно, потребуется дополнительный звонок (как со Стртулом и друзьями). Я не собираюсь публиковать полное решение домашнего задания.

fizzer 13.10.2008 10:35

Прежде всего, вы должны решить, каких представителей вы хотите узнать. Например, является ли 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, не так ли?

Jonathan Leffler 13.10.2008 03:05
Ответ принят как подходящий

В 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) завершится ошибкой?

fizzer 13.10.2008 10:40

Пример не должен быть полным: он просто предлагает правильный шаблон, объединяющий перечисление, объединение и функцию поиска типов. Пользователь должен адаптировать эти символы к своим потребностям, таким как поддерживаемые типы, как он будет обрабатывать двойное число, то есть целое число, шестнадцатеричное представление и т. д.

paercebal 16.10.2008 02:11

Другие вопросы по теме