6

我正在为 LMS 构建一个 SCORM 2004 javascript API,SCORM 2004 要求之一是传递给它的时间间隔必须遵循以下格式。有谁知道这个的正则表达式是什么?我试图将我的思想包裹在它周围,但无济于事。注意:P 必须始终是第一个字符。

P[yY][mM][dD][T[hH][nM][s[.s]S]] 其中:

  • y:年数(整数,>=0,不限)
  • m:月数(整数,>=0,无限制)
  • d:天数(整数,>=0,不限)
  • h:小时数(整数,>=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分钟

任何帮助将不胜感激。

谢谢!

更新:

我添加了一些必须保留的附加标准 -

  • 代号 P 应在场
  • 如果年、月、日、小时、分钟或秒的值为零,则可以省略该值和相应的字符字面指定,但除指定符 P 外,至少应存在一个字符字面指示符和值
  • 如果不使用所有时间分量(小时、分钟和秒),则应省略指示符 T。零值可以与任何时间分量(例如,PT0S)一起使用
4

8 回答 8

5

这是我使用的正则表达式;

^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)?)?$ 
于 2011-04-14T13:32:59.583 回答
1

用于[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)
于 2009-08-20T16:32:00.727 回答
1

JavaScript 不支持/x(自由间距或注释模式),因此请在使用此正则表达式之前删除空格。

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

每个(?=.)前瞻都断言在匹配的那个点上至少还有一个字符。这意味着以下组中的至少一个(即 P 之后的 Y、M、D 或 T 组,以及 T 之后的 H、M 或 S 组)必须匹配,即使它们都是可选的。这满足了您更新的规范中添加的第二个要求。

于 2009-08-20T19:32:28.693 回答
1

也许这是语义,但是 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 之外,至少应存在一个字符文字指示符和值

必须有一种方法可以为这个正则表达式添加一个数值检查,但是我的正则表达式-fu 不是那么强大。:)

于 2010-08-17T07:55:20.300 回答
1

对于它的价值,我已经将接受的答案改编为与 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>
于 2013-06-19T20:40:02.527 回答
0

我们的 SCORM 引擎实现使用了与上述类似的正则表达式的组合,并且一些基本的 JavaScript 逻辑会做进一步的验证。

于 2009-08-27T15:58:34.310 回答
0

我正在使用这个表达式:

^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" 之类的值不匹配:要匹配的指示符必须伴随一个数字。

于 2011-05-03T09:41:08.697 回答
0

根据先前接受的答案,我为 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 中找不到如何做同样的事情,因为没有命名组就无法以可靠的方式访问可选组。

于 2018-06-13T08:06:03.517 回答