Написать форму EBNF за год/месяц/день

Я хочу найти решение следующей проблемы, но мне нужно написать EBNF времени в двух форматах, год-месяц-день и месяц-день-год, чтобы увидеть различия:

Определите одно преимущество записи дат в виде структурированного целого числа в форме: год, месяц, день (1954-02-10) вместо обычного порядка (02-10-1954).

Формат: год-месяц-день. Вот что я придумал:

<NonZeroDigit> ::= ("1" | "2" | ... | "9")
<Month> ::= ( "0" <NonZeroDigit> ) | ( "1" ( "0" | "1" | "2" ) ) 
<Day> ::= ( "0" <NonZeroDigit> ) | ( ("1" | "2") <NonZeroDigit> ) | ("3" ( "0" | "1" ) )
<Year> ::= ( "000" <NonZeroDigit> ) | 
            ( "00" <NonZeroDigit> <NonZeroDigit> ) | 
            ( "0" <NonZeroDigit> <NonZeroDigit> <NonZeroDigit> ) | 
            ( "1"  <NonZeroDigit> <NonZeroDigit> <NonZeroDigit>) |
            ( "20" <NonZeroDigit> <NonZeroDigit> ) )

Год идет до 2099, что, я думаю, нормально, и эти правила работают, но есть ли лучший способ написать EBNF того времени? Я что-то пропустил?


person Vlad    schedule 13.03.2016    source источник
comment
Можно ли разрешить такую ​​дату, как 31 февраля? Если это так, вы можете упростить определение ‹Digit› ::= ‹NonZeroDigit› | 0 и пусть год будет четырехзначным. Вы дойдете до 9999 года. В противном случае вам придется различать месяцы, имеющие 28,30,31 день. А как насчет високосных лет, когда в феврале 29 дней?   -  person Roland    schedule 13.03.2016
comment
Да, забыл эти вещи, ха-ха. Проверю снова. Но я на правильном пути?   -  person Vlad    schedule 13.03.2016
comment
да. Все дело в том, чтобы получить правильные группы и не повторяться слишком много. И еще: вам может понадобиться включить тире, когда вы соедините все это вместе, чтобы определить ‹Дата›.   -  person Roland    schedule 13.03.2016


Ответы (1)


Итак, решение, которое я придумал, таково:

<FebruaryNum> ::= "02"
<Dash> ::= "-"
<NonLeapDigit> ::= "1" | "2" | "3" | "5" | "6" | "7"
<LeapDigit> ::= "4" | "8"
<NonZeroOrNineDigit> ::= <NonLeapDigit> | <LeapDigit>
<Digit> ::= "0" | <NonZeroOrNineDigit> | "9"
<ThreeDigits> ::= <Digit> <Digit> <Digit>
<DaysFebNonLeap> ::= ( "0" <Digit> ) | ( ("1" | "2" ) ( <NonZeroOrNineDigit> | "0")
<DaysFebLeap> ::= <DaysFebNonLeap> | "29"
<Days30> ::= <DaysFebLeap> | "30"
<Days31> ::= <Days30> | "31" 
<LeapYear> ::= <ThreeDigits> ( <LeapDigit> | "0" )
<NonLeapYear> ::= <ThreeDigits> ( "0" | <NonLeapDigit> | "9" )
<Month31Days> ::= ( ( "0" ( "1" | "3" | "5" | "7" | "8") ) | ( "1" ( "0" | "2" ) ) ) <Dash> <Days31>
<Month30Days> ::= ( ( "0" ( "4" | "6" | "9" ) ) | "11" ) <Dash> <Days30> 
<FebruaryLeap> ::= <FebruaryNum> <Dash> <DaysFebLeap>
<FebruaryNonLeap> ::= <FebruaryNum> <Dash> <DaysFebNonLeap>

<DateYearMonthDay> ::= ( <LeapYear> <Dash> ( <FebruaryLeap> | <Month30Days> | <Month31Days> ) ) | 
                        ( <NonLeapYear> <Dash> ( <FebruaryNonLeap> | <Month30Days> | <Month31Days> ))

И преимущество, которое вы получаете, когда пишете год-месяц-день вместо дня-месяца-года или месяца-дня-года, заключается в том, что день зависит от месяца, а месяц зависит от года, поэтому проще программировать автоматы, которые могут печатать дата в формате год-месяц-день.

person Vlad    schedule 14.03.2016