2009-08-20 10 views
5

Estoy construyendo una API de JavaScript SCORM 2004 para un LMS, y uno de los requisitos de SCORM 2004 es que los intervalos de tiempo pasados ​​dentro de este deben seguir el siguiente formato. ¿Alguien sabe cuál sería la expresión regular de esto? Estoy tratando de entenderlo, pero fue en vano. Nota: P siempre debe ser el primer personaje.SCORM 2004 Formato de hora - Expresión regular?

P [aa] [mM] [dD] [T [hh] [nM] [S [.s] S]] donde:

  • y: El número de años (entero ,> = 0, no restringida)
  • m: El número de meses (entero,> = 0, no restringida)
  • d: El número de días (entero,> = 0, no restringido)
  • h : El número de horas (entero,> = 0, no restringido)
  • n: El nu mber de minutos (entero,> = 0, no restringido)
  • s: la cantidad de segundos o fracción de segundos (real o entero,> = 0, no restringido). Si se utilizan fracciones de segundo, SCORM restringe aún más la cadena a con un máximo de 2 dígitos (por ejemplo, 34.45 - válido, 34.45454545 - no válido).
  • Los caracteres literales designadores de carácter P, Y, M, D, T, H, M y S aparecerán si el correspondiente valor distinto de cero está presente.
  • Se admitirá el relleno cero de los valores. El relleno cero no cambia el valor entero del número representado por un conjunto de caracteres. Para el ejemplo , PT05H es equivalente a PT5H y PT000005H.

Ejemplo -

  • P1Y3M2DT3H indica un período de tiempo de 1 año, 3 meses, 2 días y 3 horas
  • PT3H5M indica un período de tiempo de 3 horas y 5 minutos

Cualquier ayuda sería muy apreciada.

Gracias!

ACTUALIZACIÓN:

he añadido algunas normas adicionales que deben mantenerse -

  • El designador P estará presente
  • Si el valor de años, meses, días, horas, minutos o segundos es cero, el valor y la correspondiente designación literal de carácter pueden ser omitidos, pero al menos un carácter r designador literal y valor será presente además del designador P
  • El designador T deberá omitirse si no se utilizan todos los componentes de tiempo (horas, minutos y segundos).Un valor cero puede ser utilizado con cualquiera de los componentes de tiempo (por ejemplo, PT0S)

Respuesta

5

Aquí está la expresión regular que uso;

^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)?)?$ 
+0

adapté esto para ColdFusion, y yo encontrado lo que creo que es un error (al menos en CF) para la parte de "segundos". Creo que la parte de los segundos debe ser (\ d + (?: \. \ D {1,2})? S | S)? – hairbo

0

Use [0-9] para que coincida con cualquier número. + para que coincida con 1 o más repeticiones. ? para que coincida con 0 o 1 repeticiones. () para agrupar y extraer la salida.

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

Esta expresión regular es demasiado permisivo para segundos y coincidirá con los valores como ' '1.1.1.1.1''. – FMc

+0

Esta expresión funciona a excepción de los detalles que FM comentó. Lo modifiqué un poco para permitir que un 0 esté en lugar de 0M por ejemplo (según los estándares), así que ahora tengo: P ((([0-9] + Y) | 0)? (([0 -9] + M) | 0)? (([0-9] + D) | 0)?) (T (([0-9] + H) | 0)? (([0-9] + M) | 0)? (([0-9.] + S) | 0)?) También encontré requisitos adicionales y he actualizado la pregunta original. –

+0

"0 en lugar de 0M"? ¿Dónde está eso en la especificación? –

1

JavaScript no admite /x (modo libre espaciado o comentarios), por lo que eliminar el espacio en blanco de esta expresión regular antes de usarlo.

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

Cada (?=.) búsqueda hacia delante afirma que hay por lo menos un carácter que queda en ese punto en el partido. Eso significa que al menos uno de los siguientes grupos (es decir, el grupo Y, M, D o T después de la P, y el grupo H, M o S después de la T) tiene que coincidir, aunque todos son opcionales. Eso satisface el segundo de los requisitos adicionales en su especificación actualizada.

+0

Muchas gracias por su expresión regular, pero encontré algunos ejemplos que se rompen. Creo que cada uno de los siguientes son válidos en la especificación y deben ser verdaderos pero devueltos falsos (¡disculpas si me equivoco!): PT00S (la porción de fecha completa puede omitirse según la especificación, y los valores cero son aceptables para H/M/Ss) PYMDTH23M15S (letras pueden estar presentes w/o números) PYMDT2HM15.23S (letras pueden estar presentes w/o números) – pipwerks

0

Nuestra implementación de motor SCORM utiliza una combinación de una expresión regular similar a las anteriores y algunas lógicas básicas de JavaScript hacen más validación.

1

Quizás es semántica, pero esta parte de la especificación SCORM puede interpretarse en el sentido de literales están permitidos incluso si un valor no se suministra:

Los caracteres literales designadores P, Y, M, D , T, H, M y S aparecerán si el valor distinto de cero correspondiente es presente.

"aparecerá", lo que significa que un literal DEBE estar presente si el número correspondiente está presente; no dice "SÓLO aparecerá" si el número correspondiente está presente.

he modificado expresiones regulares de Alan para manejar esta posibilidad (gracias, Alan):

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

El único error que he encontrado hasta ahora es un fracaso a la bandera de una cadena que no tiene valores numéricos especificados, tales como 'PTS'. El mínimo de acuerdo con la especificación es "P", seguido de un único valor y designación de acompañamiento, tales como P1Y (= 1 año) o PT0S (= 1 segundo):

al menos un carácter literal designador y el valor deberá estar presente además del designador P

tiene que haber una manera de añadir un cheque por un valor numérico a esta expresión regular, pero mi expresión regular-fu no es tan fuerte. :)

0

estoy usando esta expresión:

^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))))?$ 

Esta expresión no coincide con un valor como "PYMDT0H": un dígito debe acompañar al designador a ser igualada.

0

Por lo que vale, he adaptado la respuesta aceptada para su uso con Cold Fusion. Pensé que algunas personas podrían encontrarlo útil, así que pensé en publicarlo. Como se señaló anteriormente, CF bombardeó la implementación de segundos anterior, así que lo modifiqué. No estoy seguro si eso significa que es un error general de RegEx en el ejemplo anterior, o si CF y JS tienen diferentes implementaciones de RegEx. De todos modos, aquí está la CF expresiones regulares, con comentarios (porque, ya sabes, las expresiones de otra manera regular son galimatías completa):

<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"> 

Después de eso, se ejecuta en contra de su cadena como esta:

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

que devuelve una matriz de subexpresiones, que se puede iterar sobre conseguir las piezas discretas:

<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> 
Cuestiones relacionadas