SCORM 2004 时间格式 - 正则表达式?

发布于 2024-08-02 15:12:24 字数 1063 浏览 5 评论 0原文

我正在为 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 应出现
  • 如果年、月、日、小时、分钟或秒的值为 零,该值和对应的 字符字面指定可能是 省略,但至少有一个字符 文字指示符和值应为 除了指示符之外还存在
  • 如果所有时间组成部分(小时、 分钟和秒)不被使用。一个 零值可以与任何一个一起使用 时间组件(例如PT0S)

I am building a SCORM 2004 javascript API for an LMS, and one of the SCORM 2004 requirements is that timeintervals passed into it must follow the following format. Does anyone know what the regular expression of this would be? I am trying to wrap my mind around it, but to no avail. Note: P must always be the first character.

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

  • y: The number of years (integer, >= 0, not restricted)
  • m: The number of months (integer, >=0, not restricted)
  • d: The number of days (integer, >=0, not restricted)
  • h: The number of hours (integer, >=0, not restricted)
  • n: The number of minutes (integer, >=0, not restricted)
  • s: The number of seconds or fraction of seconds (real or integer, >=0, not
    restricted). If fractions of a second are used, SCORM further restricts the string to
    a maximum of 2 digits (e.g., 34.45 – valid, 34.45454545 – not valid).
  • The character literals designators P, Y, M, D, T, H, M and S shall appear if the
    corresponding non-zero value is present.
  • Zero-padding of the values shall be supported. Zero-padding does not change the
    integer value of the number being represented by a set of characters. For
    example, PT05H is equivalent to PT5H and PT000005H.

Example -

  • P1Y3M2DT3H indicates a period of time of 1 year, 3 months, 2 days and 3
    hours
  • PT3H5M indicates a period of time of 3 hours and 5 minutes

Any help would be greatly appreciated.

Thanks!

UPDATE:

I have added some additional standards that must be kept -

  • The designator P shall be present
  • If the value of years, months, days, hours, minutes or seconds is
    zero, the value and corresponding
    character literal designation may be
    omitted, but at least one character
    literal designator and value shall be
    present in addition to the designator
    P
  • The designator T shall be omitted if all of the time components (hours,
    minutes and seconds) are not used. A
    zero value may be used with any of the
    time components (e.g., PT0S)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

可是我不能没有你 2024-08-09 15:12:24

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

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

Here is the regex i use;

^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)?)?$ 
你另情深 2024-08-09 15:12:24

使用[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)

Use [0-9] to match any numeral. + to match 1 or more repetitions. ? to match 0 or 1 repetitions. () to group and extract the output.

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)
献世佛 2024-08-09 15:12:24

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 组)必须匹配,即使它们都是可选的。这满足了更新规范中第二个添加的要求。

JavaScript doesn't support /x (free-spacing or comments mode), so remove the whitespace from this regex before using it.

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

Each (?=.) lookahead asserts that there's at least one character remaining at that point in the match. That means at least one of the following groups (ie, the Y, M, D or T group after the P, and the H, M or S group after the T) has to match, even though they're all optional. That satisfies the second of the added requirements in your updated spec.

痕至 2024-08-09 15:12:24

就其价值而言,我已经调整了已接受的答案以与冷聚变一起使用。我想有些人可能会觉得它有用,所以我想我会发布它。如上所述,CF 轰炸了上面的秒实现,所以我修改了它。我不确定这是否意味着上面示例中的常规正则表达式错误,或者 CF 和 JS 是否有不同的正则表达式实现。无论如何,这是 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>

For what it's worth, I've adapted the accepted answer for use with Cold Fusion. I thought some folks might find it useful, so I figured I'd post it. As noted above, CF bombed on the seconds implementation above, so I modified it. I'm not sure if that means it's a general RegEx error in the above example, or if CF and JS have different RegEx implementations. Anyway, here's the CF RegEx, complete with comments (because, you know, otherwise regular expressions are complete gibberish):

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

After that, you run it against your string like this:

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

That returns an array of subexpressions, which you can iterate over to get the discreet parts:

<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>
帅哥哥的热头脑 2024-08-09 15:12:24

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

Our SCORM Engine implementation uses a combination of a regular expression similar to the ones above and some basic JavaScript logic do do further validation.

忆沫 2024-08-09 15:12:24

也许这是语义上的问题,但是 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

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

Maybe it's semantics, but this part of the SCORM spec can be interpreted to mean literals are allowed even if a value isn't supplied:

The character literals designators P,
Y, M, D, T, H, M and S shall appear if
the corresponding non-zero value is
present.

"shall appear" meaning a literal MUST be present if the corresponding number is present; it doesn't say "shall ONLY appear" if the corresponding number is present.

I modified Alan's regex to handle this possibility (thanks, Alan):

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

The only bug I've found so far is a failure to flag a string that has no numeric values specified, such as 'PTS'. The minimum according to the spec is "P" followed by a single value and accompanying designation, such as P1Y (= 1 year) or PT0S (= 1 second):

at least one character literal
designator and value shall be present
in addition to the designator P

There must be a way to add a check for a numeric value to this regex, but my regex-fu is not that strong. :)

滿滿的愛 2024-08-09 15:12:24

我正在使用这个表达式:

^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”之类的值不匹配:数字必须伴随指示符才能匹配。

I'm using this expression:

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

This expression does not match a value like "PYMDT0H" : a digit must accompany the designator to be matched.

醉殇 2024-08-09 15:12:24

根据之前接受的答案,我为PCRE(PHP,ruby,Ecmascript 2018,...)制作了这个捕获正则表达式: https://regex101.com/r/KfMs1I/6


^P
(?=\w*\d)
(?:(?<年>\d+)Y|Y)?
(?:(?<月份>\d+)M|M)?
(?:(?<天数>\d+)D|D)?
(?:
时间
(?:(?<小时>\d+)H|H)?
(?:(?<分钟>\d+)M|M)?
(?:
(?<秒>;
\d+
(?:
\.
\d{1,2}
)?
)S
|
S
)?
)?$
不幸

的是,我无法找到如何在当前的 JS 中执行相同的操作,因为如果没有命名组,则无法以可靠的方式访问可选组。

Based on the previously accepted answer, I've made this capturing regex for 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
)?
)?$

Unfortunately I can't find how to do the same in current JS, because the optional groups cannot be accessed in a reliable way without named groups.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文