Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.78
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
#1

Парсинг и валидация записи числа - C++

04.01.2013, 10:16. Просмотров 1202. Ответов 35
Метки нет (Все метки)

Дана запись числа:
Все дробные числа пишутся в знаковом десятичном формате с плавающей запятой со знаковым порядком. Знак + числа в целом опускается. Если число равно нолю, то: знак числа в целом опускается, а порядок равен нолю. Знак порядка опускается только, если порядок равен нолю. Разделитель мантиссы и порядка – буква "E" верхнего регистра. Разделитель целой и дробной части мантиссы – точка.
, требуется выполнить её валидацию и вернуть double в значении функции и код ошибки через параметр. Как нибудь я это распарсю, вопрос в том, как сделать лучше и как сделать валидацию.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
04.01.2013, 10:16     Парсинг и валидация записи числа
Посмотрите здесь:
валидация числа C++
C++ Проверить, есть ли в записи числа m цифры, совпадающие с цифрами в записи числа n
Есть в записи числа m цифры, которые совпадают с цифрами в записи числа n C++
C++ Парсинг файла игнорирует числа
C++ Парсинг файлов, найти целые числа
Даны натуральные числа n, k. Проверить, есть ли в записи числа n (в степени k) цифра m C++
C++ Даны натуральные числа n, k. Проверить, есть ли в записи числа nk цифра m
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
iifat
2225 / 1378 / 102
Регистрация: 05.06.2011
Сообщений: 3,799
04.01.2013, 11:05     Парсинг и валидация записи числа #2
Цитата Сообщение от taras atavin Посмотреть сообщение
Как нибудь я это распарсю
Парси, имхо, и не парься. Для сложных грамматик есть хорошие и плохие способы, но для вот этой -- все они одинаковы, кроме невообразимо тупых. Тебе настолько тупых написать, имхо, слобО.
Валидация -- ну, просто держи в голове, что могут быть ошибки. То бишь, например, был бы уверен, что ошибок нет -- отсчитал бы цифры целой части, проверил на точку, если нет -- пропускаешь символ и читаешь порядок; для валидации надо проверить, что точка либо "Е".
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 11:36  [ТС]     Парсинг и валидация записи числа #3
Цитата Сообщение от iifat Посмотреть сообщение
но для вот этой -- все они одинаковы, кроме невообразимо тупых.
А может я именно такой и сочиню?

Добавлено через 25 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
double ParseDouble(const
                   std::string     &Buffer,
                   TParseXSMResult &ResultCode)
{
 double        Result;
 double        d;
 size_t        re;
 size_t        de;
 size_t        i;
 size_t        L;
 size_t        p;
 size_t        e;
 unsigned char c;
 ResultCode=TPXSMRNoError;
 Result=0.0;
 L=Buffer.length();
 for (i=0; i<=L; ++i)
 {
  c=Buffer[i];
  if (c=='.')
  {
   p=i;
   break;
  }
 }
 for (i=p+1; i<=L; ++i)
 {
  c=Buffer[i];
  if (c=='E')
  {
   e=i;
   break;
  }
 }
 Result=0.0;
 for (d=0.1, i=p+1; i<e; ++i, d/=10.0)
 {
  c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': Result+=d;
   break;
   case '2': Result+=2.0*d;
   break;
   case '3': Result+=3.0*d;
   break;
   case '4': Result+=4.0*d;
   break;
   case '5': Result+=5.0*d;
   break;
   case '6': Result+=6.0*d;
   break;
   case '7': Result+=7.0*d;
   break;
   case '8': Result+=8.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 for (d=1.0, i=p-1; i>0; ++i, d*=10.0)
 {
  c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': Result+=d;
   break;
   case '2': Result+=2.0*d;
   break;
   case '3': Result+=3.0*d;
   break;
   case '4': Result+=4.0*d;
   break;
   case '5': Result+=5.0*d;
   break;
   case '6': Result+=6.0*d;
   break;
   case '7': Result+=7.0*d;
   break;
   case '8': Result+=8.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 c=Buffer[i];
 if (c=='-')
 {
  Result=-Result;
 }
 er=1;
 for (de=1, i=L-1; i>e; --i)
 {
    c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': re+=d;
   break;
   case '2': re+=2*de;
   break;
   case '3': re+=3*de;
   break;
   case '4': re+=4*de;
   break;
   case '5': re+=5*de;
   break;
   case '6': re+=6*de;
   break;
   case '7': re+=7*de;
   break;
   case '8': re+=8*de;
   break;
   case '9': re+=9*de;
   break;
   case '9': re+=9*de;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 c=Buffer[e+1];
 if (c=='-')
 {
  for (; re>0; --re)
  {
   Result/=10.0;
  }
 }
 else
 {
  for (; re>0; --re)
  {
   Result*=10.0;
  }
 }
 return Result;
}
. Я даже не очень понимаю, есть ли здесь дыры в валидации.

Добавлено через 3 минуты
Цитата Сообщение от iifat Посмотреть сообщение
Тебе настолько тупых написать, имхо, слобО.
Сразу видно, что ты не видел моего парсинга xsm, в котором парсер подэлемента берёт на разбор родительский элемент и ищет там своё.
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,012
04.01.2013, 11:40     Парсинг и валидация записи числа #4
По-хорошему, надо описать грамматику и построить по ней конечный автомат. Т.е. определить множество состояний, входной алфавит, функцию переходов, функцию выхода. Когда эта работа проделана, останется уже тупо механическое написание кода. Подробнее не скажу, поскольку сам это делал давно и не помню деталей.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 11:41  [ТС]     Парсинг и валидация записи числа #5
Я вообще не знаком ни с грамматиками, ни с конечными автоматами.
v.a.l.i.d
412 / 377 / 10
Регистрация: 21.09.2012
Сообщений: 913
04.01.2013, 11:44     Парсинг и валидация записи числа #6
Цитата Сообщение от taras atavin Посмотреть сообщение
case '9': Result+=9.0*d;
break;
case '9': Result+=9.0*d;
break;
строчки 59 - 62 почему то повторяются
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 11:45  [ТС]     Парсинг и валидация записи числа #7
А так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
double ParseDouble(const
                   std::string     &Buffer,
                   TParseXSMResult &ResultCode)
{
 double        Result;
 double        d;
 size_t        re;
 size_t        de;
 size_t        i;
 size_t        L;
 size_t        p;
 size_t        e;
 unsigned char c;
 ResultCode=TPXSMRNoError;
 Result=0.0;
 L=Buffer.length();
 for (i=0; i<=L; ++i)
 {
  c=Buffer[i];
  if (c=='.')
  {
   p=i;
   break;
  }
 }
 for (i=p+1; i<=L; ++i)
 {
  c=Buffer[i];
  if (c=='E')
  {
   e=i;
   break;
  }
 }
 Result=0.0;
 for (d=0.1, i=p+1; i<e; ++i, d/=10.0)
 {
  c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': Result+=d;
   break;
   case '2': Result+=2.0*d;
   break;
   case '3': Result+=3.0*d;
   break;
   case '4': Result+=4.0*d;
   break;
   case '5': Result+=5.0*d;
   break;
   case '6': Result+=6.0*d;
   break;
   case '7': Result+=7.0*d;
   break;
   case '8': Result+=8.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 for (d=1.0, i=p-1; i>0; ++i, d*=10.0)
 {
  c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': Result+=d;
   break;
   case '2': Result+=2.0*d;
   break;
   case '3': Result+=3.0*d;
   break;
   case '4': Result+=4.0*d;
   break;
   case '5': Result+=5.0*d;
   break;
   case '6': Result+=6.0*d;
   break;
   case '7': Result+=7.0*d;
   break;
   case '8': Result+=8.0*d;
   break;
   case '9': Result+=9.0*d;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 c=Buffer[i];
 if (c=='-')
 {
  Result=-Result;
 }
 er=1;
 for (de=1, i=L-1; i>e; --i)
 {
    c=Buffer[i];
  switch (c)
  {
   case '0':
   break;
   case '1': re+=d;
   break;
   case '2': re+=2*de;
   break;
   case '3': re+=3*de;
   break;
   case '4': re+=4*de;
   break;
   case '5': re+=5*de;
   break;
   case '6': re+=6*de;
   break;
   case '7': re+=7*de;
   break;
   case '8': re+=8*de;
   break;
   case '9': re+=9*de;
   break;
   default : ResultCode|=TPXSMRParseError;
   return Result;
  }
 }
 c=Buffer[e+1];
 if (c=='-')
 {
  for (; re>0; --re)
  {
   Result/=10.0;
  }
 }
 else
 {
  for (; re>0; --re)
  {
   Result*=10.0;
  }
 }
 return Result;
}
?
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,012
04.01.2013, 11:46     Парсинг и валидация записи числа #8
Думаю, для данной задачи лучше все-таки потратить время и ознакомиться с материалом. Как результат - на выходе получится более простой код, который как минимум будет проще поддерживать и отлаживать.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 11:47  [ТС]     Парсинг и валидация записи числа #9
Цитата Сообщение от 0x10 Посмотреть сообщение
Думаю, для данной задачи лучше все-таки потратить время и ознакомиться с материалом.
А где?
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,012
04.01.2013, 11:52     Парсинг и валидация записи числа #10
Гугл подсказывает, что есть книжка Ахо А., Ульман Дж. "Теория синтаксического анализа, перевода и компиляции". Обратить внимание на лексический анализ.
OhMyGodSoLong
~ Эврика! ~
1243 / 992 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
04.01.2013, 11:53     Парсинг и валидация записи числа #11
Множить и собирать по десятичным циферкам не стоит (точность-точность). И ещё стоит проверять величину порядка, чтобы влезла. И желательно ж ещё бесконечности и NaN как-то парсить.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 12:04  [ТС]     Парсинг и валидация записи числа #12
Где в первом посте хоть слово про нан и бесконечность? Запись валидна только тогда, когда в ней число.

Добавлено через 33 секунды
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
И ещё стоит проверять величину порядка, чтобы влезла.
А как?
OhMyGodSoLong
~ Эврика! ~
1243 / 992 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
04.01.2013, 12:24     Парсинг и валидация записи числа #13
Ну, как... Для того же IEEE-double (двоичный) порядок должен принадлежать отрезку [–1022; +1023]. –1023 и +1024 используются для нанов, бесконечностей, денормализованных чисел и нуля, а не влезающие в [–1023; +1024] вообще не представимы.
iifat
2225 / 1378 / 102
Регистрация: 05.06.2011
Сообщений: 3,799
04.01.2013, 13:34     Парсинг и валидация записи числа #14
Цитата Сообщение от taras atavin Посмотреть сообщение
for (i=0; i<=L; ++i)
Цитата Сообщение от taras atavin Посмотреть сообщение
for (i=p+1; i<=L; ++i)
Мнэээ... Ну, ты наворотил... Во-первых, навскидку, <L в обоих местах. Во-вторых, как точка, так и Е (в смысле, порядок) могут отсутствовать.
Я б таки предложил внутреннюю функу, парсящую максимальное целое число, выдающую его и количество цифр. Вызываем её для строки, проверяем, если дальше точка, вызываем ещё раз для куска строки после точки.
Примерно так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int sliceInt (char *& Pointer) {
  int res = 0;
  while (*Pointer) {
    if (*Pointer >= '0' && *Pointer <= '9') {
      res += *Pointer - '0';
      ++Pointer
    } {
      break;
    }
  }
  return res;
}
 
double ParseDouble(const char *const Buffer,
                   TParseXSMResult &ResultCode)
{ double        Result;
  char *p = Buffer;
  Result = sliceInt (p);
  if (*p=='.') {char *p0 = ++p; int after_p = sliceInt (p); Result += after_p * 0.1 ^ (p-p0);}
  if (*p=='E') {++p; int exp_p = sliceInt (p); Result *= 10 ^ exp_p;}
  if (*p) {error} // неведомые символы в конце строки
}
Очень приблизительно. И со std::ctring я не помню в точности как работать, так что это -- идея, не прога.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.01.2013, 17:06     Парсинг и валидация записи числа
Еще ссылки по теме:
Для натурального числа определить истинность предиката «все цифры в записи числа равны» C++
Задано два натуральных числа: m и n. Определить, сколько цифр содержится в десятичной записи числа m^n. C++
Составить программу,которая для любого натурального числа печатает количество цифр в записи этого числа C++
C++ Для каждого числа последовательности вывести новое число, которое получится после записи цифр числа в обратном порядке
Составить программу для нахождения числа, которое образуется из данного натурального числа при записи его цифр в обратном порядке C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 17:06  [ТС]     Парсинг и валидация записи числа #15
Цитата Сообщение от iifat Посмотреть сообщение
Во-вторых, как точка, так и Е (в смысле, порядок) могут отсутствовать.
Тогда исходные данные не валидны, читай первый пост. Ноль пишется только "0.0E0" и ни как иначе, единица "+1.0E0".
Yandex
Объявления
04.01.2013, 17:06     Парсинг и валидация записи числа
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru