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

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

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

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

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

Дана запись числа:
Все дробные числа пишутся в знаковом десятичном формате с плавающей запятой со знаковым порядком. Знак + числа в целом опускается. Если число равно нолю, то: знак числа в целом опускается, а порядок равен нолю. Знак порядка опускается только, если порядок равен нолю. Разделитель мантиссы и порядка – буква "E" верхнего регистра. Разделитель целой и дробной части мантиссы – точка.
, требуется выполнить её валидацию и вернуть double в значении функции и код ошибки через параметр. Как нибудь я это распарсю, вопрос в том, как сделать лучше и как сделать валидацию.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
04.01.2013, 10:16     Парсинг и валидация записи числа
Посмотрите здесь:

Составить программу для нахождения числа, которое образуется из данного натурального числа при записи его цифр в обратном порядке C++
Задано два натуральных числа: m и n. Определить, сколько цифр содержится в десятичной записи числа m^n. C++
валидация числа C++
Составить программу,которая для любого натурального числа печатает количество цифр в записи этого числа C++
C++ Парсинг файла игнорирует числа
Есть в записи числа m цифры, которые совпадают с цифрами в записи числа n C++
C++ Для каждого числа последовательности вывести новое число, которое получится после записи цифр числа в обратном порядке
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
iifat
2206 / 1359 / 101
Регистрация: 05.06.2011
Сообщений: 3,745
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
2456 / 1628 / 238
Регистрация: 24.11.2012
Сообщений: 4,003
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
2456 / 1628 / 238
Регистрация: 24.11.2012
Сообщений: 4,003
04.01.2013, 11:46     Парсинг и валидация записи числа #8
Думаю, для данной задачи лучше все-таки потратить время и ознакомиться с материалом. Как результат - на выходе получится более простой код, который как минимум будет проще поддерживать и отлаживать.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 11:47  [ТС]     Парсинг и валидация записи числа #9
Цитата Сообщение от 0x10 Посмотреть сообщение
Думаю, для данной задачи лучше все-таки потратить время и ознакомиться с материалом.
А где?
0x10
2456 / 1628 / 238
Регистрация: 24.11.2012
Сообщений: 4,003
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
2206 / 1359 / 101
Регистрация: 05.06.2011
Сообщений: 3,745
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 я не помню в точности как работать, так что это -- идея, не прога.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 17:06  [ТС]     Парсинг и валидация записи числа #15
Цитата Сообщение от iifat Посмотреть сообщение
Во-вторых, как точка, так и Е (в смысле, порядок) могут отсутствовать.
Тогда исходные данные не валидны, читай первый пост. Ноль пишется только "0.0E0" и ни как иначе, единица "+1.0E0".
iifat
2206 / 1359 / 101
Регистрация: 05.06.2011
Сообщений: 3,745
04.01.2013, 18:35     Парсинг и валидация записи числа #16
Цитата Сообщение от taras atavin Посмотреть сообщение
Тогда исходные данные не валидны
Не вопрос. Прога-то твоя вылетит! А не должна. Об том и валидация.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
04.01.2013, 18:45  [ТС]     Парсинг и валидация записи числа #17
А как?
iifat
2206 / 1359 / 101
Регистрация: 05.06.2011
Сообщений: 3,745
04.01.2013, 19:17     Парсинг и валидация записи числа #18
Ну, как -- как обычно. Например, как я набросал чуть выше -- эта не вылетает. А вообще -- ну просто иметь в виду, что всё может быть неправильно.
В числе обязана быть точка, но может отсутствовать. Значит, надо учесть этот момент. Как? Ну, например, присваиваем p перед циклом -1, а после проверяем, что >=0, иначе выдаём код.
Да, кстати, тебе ж тут советовали грамматики и регулярные выражения. В принципе, конечно, правильно, только это полгода разбираться будешь. Если в перспективе кие-нибудь сложные парсеры -- имеет смысл, а для конкретной задачи -- имхо, нет.
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
05.01.2013, 13:43  [ТС]     Парсинг и валидация записи числа #19
Цитата Сообщение от iifat Посмотреть сообщение
Например, как я набросал чуть выше -- эта не вылетает.
А как именно реагирует?

Добавлено через 7 минут
Цитата Сообщение от iifat Посмотреть сообщение
const char *const Buffer,
А мне надо str::string.
Цитата Сообщение от iifat Посмотреть сообщение
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} // неведомые символы в конце строки
А где цикл?

Добавлено через 14 минут
Цитата Сообщение от iifat Посмотреть сообщение
Result = sliceInt (p);
И как это решит проблему? Если уж нельзя выдать сообщение, то пусть лучше вылетает. Гарантия того, что функция не проглотит нечто, не соответствующее фрагменту спецификации формата, относящемуся к именно её части файла, обязательна, код ошибки желателен, причём, без подробностей, просто TPXSMRParseError. В особо запущенных случаях пусть падает, лишь бы только не пропустить что нибудь "левое".

Добавлено через 16 минут
Проблема в том, что целые и действительные в разных системах счисления: целые шестандцатеричные, но без ведущих символов 0x, а действительные десятичные. И если вдруг должно быть действительное, а ни точки, ни E в нём не окажется, то вообще не понятно, "200" - это сколько: 200, или 512 и сколько в этой записи числа вообще ошибок.

Добавлено через 3 минуты
Цитата Сообщение от iifat Посмотреть сообщение
Да, кстати, тебе ж тут советовали грамматики и регулярные выражения. В принципе, конечно, правильно, только это полгода разбираться будешь. Если в перспективе кие-нибудь сложные парсеры -- имеет смысл, а для конкретной задачи -- имхо, нет.
Это и есть часть более сложного парсера.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.01.2013, 13:55     Парсинг и валидация записи числа
Еще ссылки по теме:

C++ Даны натуральные числа n, k. Проверить, есть ли в записи числа nk цифра m
Для натурального числа определить истинность предиката «все цифры в записи числа равны» C++
C++ Парсинг файлов, найти целые числа
C++ Проверить, есть ли в записи числа m цифры, совпадающие с цифрами в записи числа n
Даны натуральные числа n, k. Проверить, есть ли в записи числа n (в степени k) цифра m C++

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

Или воспользуйтесь поиском по форуму:
iifat
2206 / 1359 / 101
Регистрация: 05.06.2011
Сообщений: 3,745
05.01.2013, 13:55     Парсинг и валидация записи числа #20
Цитата Сообщение от taras atavin Посмотреть сообщение
А как именно реагирует?
Просто закончит разбор. А потом увидит, что разобрана не вся строка и выдаст ошибку.
C++
1
if (*p) {error} // неведомые символы в конце строки
-- я просто коркретику не стал прописывать.
Цитата Сообщение от taras atavin Посмотреть сообщение
А мне надо str::string
Прикинь, как переписать на std::string. Я из изучать пока не рвусь.
Цитата Сообщение от taras atavin Посмотреть сообщение
А где цикл?
В sliceInt -- она там тоже есть.
Цитата Сообщение от taras atavin Посмотреть сообщение
Если уж нельзя выдать сообщение, то пусть лучше вылетает
Что значит -- нельзя? Можно, и не одним способом, и совершенно различной подробности. Один из способов я тебе даже набросал. Не самый лучший, разумеется -- лучшие гораздо сложнее.
Цитата Сообщение от taras atavin Посмотреть сообщение
Проблема в том, что целые и действительные в разных системах счисления
Та ради ж бога! Зачем обсуждать задачу? Она поставлена -- и ладно! Дело ж не в том, какие числа моя съест, какие нет, хотя она, кстати, и правда слишком уж всеядна. Дело в том, что моя -- не падает на неправильных числах! Добавь туда проверок на обязательность точки, добавь, кстати, ±, которых я забыл, -- в общем, как я уже говорил, это не решение, это идея, над которой ещё немало работать.
Yandex
Объявления
05.01.2013, 13:55     Парсинг и валидация записи числа
Ответ Создать тему
Опции темы

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