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

时间:2014-10-27 19:56:59

标签: 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;
}

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

/(\d*\.){0, 1}\d+/g

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

$("div.mad").css("transition")

它回来了

top 0.4s ease 0s, left 0.5s linear 0s, opacity 3s ease 0s, padding-top 1s ease 0s

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

我破碎的解决方案

我炮制的正则表达式是

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

推理细分:

(?:[^\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

当我跑步时

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);

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

jsfiddle example

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

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

帮助?

更新1

根据评论,我更新了

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

并尝试使用RegExp.exec()(我之前已尝试过,但在更新r之前它无效)。结果是

m[0] = "top 0.4s ease 0s"
m[1] = "0.4"

m[1]会捕获第一个数字,但会忽略以下数字。

我还发现我与t.match(r)的问题是/g标志。删除它会得到与r.exec(t)相同的结果。

除了在t上分割','并在每个字词上运行正则表达式之外,有没有办法在单个正则表达式中执行此操作?

更新2

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

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

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

我要考虑的唯一修改就是将+添加到[^\d\.,]的末尾,以便减少替换次数,并通过更常见字符串中的不可思议的数量来提高性能(不是{ {1}}案例,我将在一秒钟内解释。

它可能提高性能的原因是在Javascript中,字符串是不可变的,因此为每个被删除的字符创建一个新字符串会占用时间。就我而言,那只是.css('transition-duration')。用一串

s

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

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

如果你非常关心这种通常可以忽略不计的性能提升,请做一些(阅读:很多)基准测试。唯一可能的方法就是

  1. 您正在Compaq Presario 286 MMX上运行代码,内存为64MB(即我1997年的第一台计算机)或
  2. 你在字符串的内部循环中运行这个正则表达式替换数千次,其中大部分要移除的字符是在
  3. 中进行的长时间不间断运行
  4. Internet Explorer 1.5
  5. 因此,对所选答案的修改实际上可能会降低性能,具体取决于您的浏览器以及您运行它的字符串类型,但正如我之前所说,我是一个纯粹主义者,喜欢泛化和优化,以及因此我的解释。

1 个答案:

答案 0 :(得分:2)

您需要使用RegExp.exec代替RegExp.match

如何使用RegExp.exec(来自MDN):

  

如果你的正则表达式使用" g" flag,您可以多次使用exec方法在同一个字符串中查找连续匹配。执行此操作时,搜索从正则表达式指定的str的子字符串开始,其lastIndex属性(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
}

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

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

替代

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

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

然后你可以直接遍历这个数组。