【问题标题】:jQuerys $.trim(), bug or poorly written?jQuerys $.trim()、bug 还是写得不好?
【发布时间】:2026-01-06 08:25:01
【问题描述】:

$.trim() 使用以下正则表达式修剪字符串:

/^(\s|\u00A0)+|(\s|\u00A0)+$/g

事实证明,这可能很丑陋,例如:

var mystr = '    some test --          more text            new test                                         xxx';
mystr = mystr.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, "");

这段代码挂起 Firefox 和 Chrome,它就像永远一样。 "mystr" 包含空格,但主要是 hex 160(A0) 字符。只有在没有前置 whitespace/A0 而是在字符串中的某个位置时,才会出现这个“问题”。我不知道为什么会这样。

这个表达式:

/^[\n\r\t \xA0]+|[\n\r\t \xA0]$/g

在所有测试场景中都能正常工作。也许有更好的模式?

来源:http://code.jquery.com/jquery-1.4.2.js

更新

您似乎无法复制和粘贴此示例字符串,在某些时候这些 A0 字符会被替换。 Firebug console 还将替换粘贴时的字符,您必须在单独的 html 文件/编辑器中创建自己的字符串来测试这一点。

【问题讨论】:

  • 似乎 SO 将您的 A0 转换为 20 (至少当我将您的代码剪切并粘贴到 Emacs 时)。
  • @Nick:从 1.4.2 开始使用该正则表达式
  • @All:查看 Peter Jaric 的评论和我的更新
  • 一个月前在jQuery bugtracker 中列出了一个类似的错误。灾难性的回溯,我经常这样做,但很少在代码中。
  • @jAndy,也许您应该在问题的来源中添加一个链接,以避免误解:code.jquery.com/jquery-1.4.2.js

标签: javascript jquery regex


【解决方案1】:

事实证明,这种行为是一个月前在 jQuerys bugtracker 上发布的:

http://dev.jquery.com/ticket/6605

感谢Andrew 指点我。

【讨论】:

  • 那个错误报告很有趣,因为 Trac 似乎在吃 uparrow 字符。因此,损坏的“rtrim”和建议的修复看起来都不正确。
  • jAndy - +1 我看到我一直在查看最近的提交。 (感谢@Pointy 提醒我。)但是,我仍然无法让正则表达式或$.trim()(它们相同)在Firefox 中失败。我想知道为什么会这样。
【解决方案2】:

这是一个known bug,正如 cmets 中所说,Crescent 是正确的,它在 1.4.2 中是这样的,但它已经在下一个版本中修复了。

您可以在这里测试String.prototype.trim 在您的字符串上的速度:http://jsfiddle.net/dLLVN/
我在 Chrome 中运行 79 毫秒,在 Firefox 中运行 117 毫秒,运行 100 万次...所以这将解决挂起的问题 :)

至于修复,take a look at the current source that'll be in 1.4.3,现在使用原生修剪。

3 月份有 2 次提交:


1.4.2 $.trim() function:

trim: function( text ) {
    return (text || "").replace( rtrim, "" );
},

1.4.3 $.trim() function:

//earlier: 
trim = String.prototype.trim

//new trim here
trim: trim ?
  function( text ) {
    return text == null ?
      "" : 
      trim.call( text ); 
  } :

  // Otherwise use our own trimming functionality
  function( text ) { 
    return text == null ? 
      "" :
      text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
  }

trimLefttrimRight 会有所不同,具体取决于您是否使用 IE,如下所示:

trimLeft = /^\s+/,
trimRight = /\s+$/,

// Verify that \s matches non-breaking spaces
// (IE fails on this test)
if ( !/\s/.test( "\xA0" ) ) {
  trimLeft = /^[\s\xA0]+/;
  trimRight = /[\s\xA0]+$/;
}

【讨论】:

  • 很高兴看到trimLefttrimRight 表达式也一样。
  • @jAndy - 他将它们作为链接发布。点击第一个提交链接。
  • @jAndy - 添加了相关位和分支标签的链接,以便您可以看到 git 中的更改 :)
【解决方案3】:

通常像^\s+|\s+$ 这样的表达式应该足以进行修剪,因为\s 应该匹配所有空格字符,甚至\0xa0 不间断空格1。此表达式应该运行而不会导致任何问题。

现在可能 jQuery 想要支持的某些浏览器与 \0xa0\s 不匹配,为了解决这个问题,jQuery 添加了替代品 (\s|\0xa0),以修剪掉该浏览器上的不间断空格。

通过此更改,正则表达式的第二部分看起来像(\s|\0xa0)+$,这会导致浏览器出现问题,其中\0xa0 也与\s 匹配。在包含一长串\0xa0 字符的字符串中,每个字符都可以通过\s\0xa0 进行匹配,从而导致许多替代匹配项以及可以组合不同匹配项的指数级组合。如果\0xa0这个字符序列不在字符串的末尾,那么无论\s匹配哪些空格,\0xax匹配哪些空格,都永远无法满足结尾的$条件,但是浏览器不知道这一点并尝试所有组合,可能会搜索很长时间。

您建议的简化表达式是不够的,因为 \s 应该匹配所有 unicode 空格字符,而不仅仅是众所周知的 ASCII 字符。


1根据MDC\s等价于[\t\n\v\f\r \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]

【讨论】: