Формат времени SCORM 2004 - регулярное выражение? - PullRequest
6 голосов
/ 20 августа 2009

Я создаю API-интерфейс javascript SCORM 2004 для LMS, и одно из требований SCORM 2004 состоит в том, что передаваемые в него интервалы времени должны соответствовать следующему формату. Кто-нибудь знает, каково будет это регулярное выражение? Я пытаюсь обдумать это, но безрезультатно. Примечание: P всегда должен быть первым символом.

Р [YY] [мМ] [дБ] [T [HH] [нМ] [с [.s] S]] где:

  • y: количество лет (целое число,> = 0, не ограничено)
  • m: количество месяцев (целое число,> = 0, без ограничений)
  • d: количество дней (целое число,> = 0, не ограничено)
  • ч: количество часов (целое число,> = 0, не ограничено)
  • n: количество минут (целое число,> = 0, без ограничений)
  • s: количество секунд или доля секунд (действительное или целое число,> = 0, не ограничено). Если используются доли секунды, SCORM дополнительно ограничивает строку максимум 2 цифры (например, 34,45 - действительный, 34,45454545 - недействительный).
  • Символы литералов символов P, Y, M, D, T, H, M и S должны появиться, если соответствующее ненулевое значение присутствует.
  • Должно поддерживаться заполнение нулями значений. Нулевое заполнение не меняет целочисленное значение числа, представленного набором символов. За Например, PT05H эквивалентен PT5H и PT000005H.

Пример -

  • P1Y3M2DT3H указывает период времени 1 год, 3 месяца, 2 дня и 3 часы
  • PT3H5M указывает период времени 3 часа и 5 минут

Любая помощь будет принята с благодарностью.

Спасибо!

UPDATE:

Я добавил некоторые дополнительные стандарты, которые необходимо соблюдать -

  • Обозначение P должно присутствовать
  • Если значение лет, месяцев, дней, часов, минут или секунд составляет ноль, значение и соответствующее буквенное обозначение может быть опущен, но хотя бы один символ буквальное обозначение и значение должны быть присутствует в дополнение к обозначению P
  • Обозначение T должно быть опущено, если все компоненты времени (часы, минуты и секунды) не используются. нулевое значение может быть использовано с любым из временные составляющие (например, PT0S)

Ответы [ 8 ]

5 голосов
/ 14 апреля 2011

Вот регулярное выражение, которое я использую;

^P(?=\w*\d)(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\­.\d{1,2})?S|S)?)?$ 
1 голос
/ 20 июня 2013

Для чего бы то ни было, я адаптировал принятый ответ для использования с Cold Fusion. Я думал, что некоторые люди могут найти это полезным, поэтому я решил опубликовать это. Как отмечалось выше, CF бомбил секундную реализацию выше, поэтому я модифицировал ее. Я не уверен, означает ли это, что это общая ошибка RegEx в приведенном выше примере, или CF и JS имеют разные реализации RegEx. Во всяком случае, вот CF RegEx, полный комментариев (потому что, знаете, в противном случае регулярные выражения - полная чушь):

<cfset regex = "(?x) ## allow for multi-line expression, including comments (oh, glorious comments)
            ^ ## ensure that this expression occurs at the start of the string
            P ## the first character must be a P
            (\d+Y|Y)? ## year (the ? indicates 0 or 1 times)
            (\d+M|M)? ## month
            (\d+D|D)? ## day
            (?:T ## T delineates between day and time information
            (\d+H|H)? ## hour
            (\d+M|M)? ## minute
            (\d+(?:\.\d{1,2})?S|S)? ## seconds and milliseconds.  The inner ?: ensure that the sub-sub-expression isn't returned as a separate thing
            )? ## closes 'T' subexpression
            $ ## ensure that this expression occurs at the end of the string.  In conjunction with leading ^, this ensures that the string has no extraenous characters">

После этого вы запускаете его для своей строки следующим образом:

<cfset result = reFind(regex,mystring,1,true)>

Возвращает массив подвыражений, который вы можете перебрать, чтобы получить дискретные части:

<cfloop from=1 to=#arrayLen(result.len)# index=i>
    <cfif result.len[i] GT 0>
    #mid(mystring, result.pos[i], result.len[i])#<br>
    </cfif>
</cfloop>
1 голос
/ 17 августа 2010

Возможно, это семантика, но эту часть спецификации SCORM можно интерпретировать как означающую, что литералы разрешены, даже если значение не указано:

Обозначения литералов символов P, Y, M, D, T, H, M и S должны появиться, если соответствующее ненулевое значение нет.

«должен появиться», означая, что литерал ДОЛЖЕН присутствовать, если присутствует соответствующий номер; он не говорит «ТОЛЬКО появится», если присутствует соответствующий номер.

Я изменил регулярное выражение Алана, чтобы справиться с этой возможностью (спасибо, Алан):

^P(?:\d+Y|Y)?(?:\d+M|M)?(?:\d+D|D)?(?:T(?:\d+H|H)?(?:\d+M|M)?(?:\d+(?:\.\d{1,2})?S|S)?)?$

Единственная ошибка, которую я обнаружил до сих пор, - это неспособность пометить строку, для которой не указаны числовые значения, например, 'PTS'. Минимум в соответствии со спецификацией - «P», за которым следует одно значение и соответствующее обозначение, например, P1Y (= 1 год) или PT0S (= 1 секунда):

хотя бы один символьный литерал обозначение и значение должны присутствовать в дополнение к обозначению P

Должен быть способ добавить проверку на числовое значение к этому регулярному выражению, но мое регулярное выражение не настолько сильное. :)

1 голос
/ 20 августа 2009

JavaScript не поддерживает /x (в свободном интервале или в режиме комментариев), поэтому удалите пробелы из этого регулярного выражения перед его использованием.

/^P(?=.)
 (?:\d+Y)?
 (?:\d+M)?
 (?:\d+D)?
 (?:T(?=.)
    (?:\d+H)?
    (?:\d+M)?
    (?:\d+
       (?:\.\d{1,2})?
    )?
 )?$/i

Каждый (?=.) прогнозирующий утверждает, что в этой точке в матче остается хотя бы один символ. Это означает, что по крайней мере одна из следующих групп (то есть, группа Y, M, D или T после P и группа H, M или S после T) должна совпадать, даже если они все необязательны. Это удовлетворяет второму из добавленных требований в вашей обновленной спецификации.

1 голос
/ 20 августа 2009

Используйте [0-9] для сопоставления с любой цифрой. +, чтобы соответствовать 1 или более повторений. ?, чтобы соответствовать 0 или 1 повторениям. () для группировки и извлечения выходных данных.

P(([0-9]+Y)?([0-9]+M)?([0-9]+D)?)(T([0-9]+H)?([0-9]+M)?([0-9.]+S)?)?

import re

>>> p = re.compile('P(([0-9]+Y)?([0-9]+M)?([0-9]+D)?)(T([0-9]+H)?([0-9]+M)?([0-9.]+S)?)?')

>>> p.match('P1Y3M2DT3H').groups()
('1Y3M2D', '1Y', '3M', '2D', 'T3H', '3H', None, None)

>>> p.match('P3M2DT3H').groups()
('3M2D', None, '3M', '2D', 'T3H', '3H', None, None)

>>> p.match('PT3H5M').groups()
('', None, None, None, 'T3H5M', '3H', '5M', None)

>>> p.match('P1Y3M4D').groups()
('1Y3M4D', '1Y', '3M', '4D', None, None, None, None)
0 голосов
/ 13 июня 2018

Основываясь на ранее принятом ответе, я сделал это регулярное выражение захвата для PCRE (PHP, ruby, Ecmascript 2018, ...): https://regex101.com/r/KfMs1I/6

^P (?=\w*\d) (?:(?<years>\d+)Y|Y)? (?:(?<month>\d+)M|M)? (?:(?<days>\d+)D|D)? (?: T (?:(?<hours>\d+)H|H)? (?:(?<minutes>\d+)M|M)? (?: (?<seconds> \d+ (?: \. \d{1,2} )? )S | S )? )?$

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

0 голосов
/ 03 мая 2011

Я использую это выражение:

^P(\d+Y)?(\d+M)?(\d+D)?(T(((\d+H)(\d+M)?(\d+(\.\d{1,2})?S)?)|((\d+M)(\d+(\.\d{1,2})?S)?)|((\d+(\.\d{1,2})?S))))?$

Это выражение не соответствует значению типа «PYMDT0H»: цифра должна сопровождать обозначение для сопоставления.

0 голосов
/ 27 августа 2009

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

...