在javascript中使用正则表达式捕获文本中的第一个数字

dx_*_*_dt 8 javascript regex

上下文

我有一些CSS来做转换:

div.mad {
    -webkit-transition: top .4s, left .5s linear, opacity .75s, padding-top 1s;
    transition: top .4s, left .5s linear, opacity 3s, padding-top 1s;
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试在此列表中找到最大值,这很容易与正则表达式一起使用.

/(\d*\.){0, 1}\d+/g
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我得到CSS值

$("div.mad").css("transition")
Run Code Online (Sandbox Code Playgroud)

它回来了

top 0.4s ease 0s, left 0.5s linear 0s, opacity 3s ease 0s, padding-top 1s ease 0s
Run Code Online (Sandbox Code Playgroud)

现在我的正则表达式也获得了延迟值(" 0").考虑到我试图找到最大值,那也没关系,但我心里很纯粹,我想将匹配限制在过渡时间.

破碎的解决方案

我编造的正则表达式是

/(?:[^\d\.]*)((\d*\.){0, 1}\d+)(?:s[^,]*)/g
Run Code Online (Sandbox Code Playgroud)

推理细分:

(?:[^\d\.]*)       -- non-capturing group that looks for anything that is not a digit or a decimal point
                   -- should match "top ", "left ", etc.

(                  -- begin capture group
    (\d*\.){0, 1}  -- capture ones, tens, etc + decimal point, if it exists
    \d+            -- capture tenths, hundreds, etc if decimal exists, else capture ones, tens, etc
) -- close capture group

(?:s[^,]*)         -- non-capturing group for the remainder of the transition element
Run Code Online (Sandbox Code Playgroud)

我跑的时候

var t = "top 0.4s ease 0s, left 0.5s linear 0s, opacity 3s ease 0s, padding-top 1s ease 0s";
var r = /[^\d\.]*((\d*\.){0,1}\d*)s[^,]*/g
var m = t.match(r);
Run Code Online (Sandbox Code Playgroud)

每个的结果m是:

m[0] = "top 0.4s ease 0s"
m[1] = ", left 0.5s linear 0s"
m[2] = ", opacity 3s ease 0s"
m[3] = ", padding-top 1s ease 0s"
Run Code Online (Sandbox Code Playgroud)

jsfiddle的例子

我认为非捕获组的想法是它会匹配字符,但是当您尝试访问组时忽略它们.

我有预感,我正在看比赛而不是小组,但我还没有想出如何让小组取而代之.

救命?

更新1

根据评论,我更新了

r = /(?:(?:[\,]*,)*[^\d\.]*)(\d*\.?\d+)s[^,]*/
Run Code Online (Sandbox Code Playgroud)

并尝试使用RegExp.exec()(我之前已经尝试过,但直到我更新它才能正常工作r).结果是

m[0] = "top 0.4s ease 0s"
m[1] = "0.4"
Run Code Online (Sandbox Code Playgroud)

m[1] 确实捕获了第一个数字,但它忽略了以下数字.

我还发现我遇到的问题t.match(r)/g旗帜.删除它会产生相同的结果r.exec(t).

除了拆分t',',并在每学期运行正则表达式,有没有办法在一个单一的正则表达式来做到这一点?

更新2

@Esteban Felix的替代答案显然是最好的选择.

$('div.mad').css('transition-duration').replace(/[^\d\.,]/g,'').split(',');
Run Code Online (Sandbox Code Playgroud)

TL; DR:在这种情况下使用上述内容,但这里解释了为什么在其他情况下你不应该这样做.

我将考虑的唯一修改是追加+到最后[^\d\.,],以便减少替换次数并通过更常见的字符串中的不可思议的数量来提高性能(不是这种.css('transition-duration')情况,我会在一秒钟内解释).

它可能提高性能的原因是在Javascript中,字符串是不可变的,因此为每个被删除的字符创建一个新字符串会占用时间.在我的情况下,这只是's and s's.用一串

0.4s, 0.5s, 0.75s, 1s
Run Code Online (Sandbox Code Playgroud)

空格和s永远不会彼此相邻,因此结果实际上是性能的恶化,因为现在正则表达式引擎必须在每次找到要删除的字符时检查以下字符.但是,在更常见的字符串中,您删除了大量连续字符,添加+可以提高性能.它可能不是唯一的原因是如果实现String.replace()是智能的,并且在幕后使用字符数组,只在函数末尾为新字符串分配空间.这个方面取决于浏览器,但我猜它是现代浏览器的常见情况.

值得注意的是,使用a +而不是a 是很重要的*,因为后者会匹配字符之间的每个位置,用指定的空字符串替换匹配的空字符串.我不知道javascript引擎是否会创建大量新的,相同的字符串,但它肯定无法提高性能.

如果你真的关心这个通常可以忽略不计的性能提升,那么做一些(阅读:很多)基准测试.你会看到任何差异的唯一可能方式是if

  1. 您正在Compaq Presario 286 MMX上运行代码,内存为64MB(即我1997年的第一台计算机)或
  2. 你在字符串的内部循环中运行这个正则表达式替换成千上万次,其中大多数要移除的字符是在长的,不间断的运行中
  3. Internet Explorer 1.5

因此,对所选答案的修改实际上可能会降低性能,具体取决于您的浏览器以及您运行它的字符串类型,但正如我之前所说,我是一个纯粹主义者,喜欢泛化和优化,因此我的解释.

Est*_*lix 2

您将想要使用RegExp.exec而不是RegExp.match.

使用方法RegExp.exec(来自MDN):

如果您的正则表达式使用“g”标志,则可以多次使用 exec 方法来查找同一字符串中的连续匹配项。当您这样做时,搜索从正则表达式的lastIndex属性指定的str的子字符串开始(test()也将推进lastIndex属性)。

您的代码的示例:

var t = "top 0.4s ease 0s, left 0.5s linear 0s, opacity 3s ease 0s, padding-top 1s ease 0s";
var r = /[^\d\.]*((\d*\.){0,1}\d*)s[^,]*/g
var m;
while((m = r.exec(t)) !== null) {
    console.log(m[2]); // <- number you want to extract
}
Run Code Online (Sandbox Code Playgroud)

此外,您的正则表达式存在一个小问题,导致小数点后的数字无法被捕获。更新后的正则表达式:

/(?:[^\d\.]*)(\d*\.?\d+)(?:s[^,]*)/g

选择

您也可以不查看,而是查看transition您真正关心的属性,即transition-duration

$('div.mad').css('transition-duration').replace(/[^\d\.,]/g,'').split(',');
Run Code Online (Sandbox Code Playgroud)

然后你可以直接循环这个数组。