如何知道 JavaScript string.replace() 是不是做了啥?

Posted

技术标签:

【中文标题】如何知道 JavaScript string.replace() 是不是做了啥?【英文标题】:How to know if JavaScript string.replace() did anything?如何知道 JavaScript string.replace() 是否做了什么? 【发布时间】:2011-07-12 12:51:48 【问题描述】:

replace 函数返回带有替换的新字符串,但如果没有要替换的单词,则返回原始字符串。除了将结果与原始字符串进行比较之外,有没有办法知道它是否真的替换了任何东西?

【问题讨论】:

为什么不想比较源字符串和修改后的字符串? 这是另一个 O(N) 操作。想象一下,我正在替换 100KB 的字符串。 好吧,如果替换发生在字符串的末尾,那么是的。但是无论如何,您的问题没有 O(1) 答案。如果需要,可以使用 match 然后替换,或者进行替换然后比较两个字符串。 @Alex - 严格来说,“另一个 O(N)”仍然是 O(N)。 javascript 中操作 100kb 的字符串通常是一个非常非常糟糕的主意。 【参考方案1】:

一个简单的选择是在替换之前检查匹配项:

var regex = /i/g;
var newStr = str;

var replaced = str.search(regex) >= 0;
if(replaced)
    newStr = newStr.replace(regex, '!');

如果您也不想这样,您可以滥用replace 回调来一次性实现:

var replaced = false;
var newStr = str.replace(/i/g, function(token)replaced = true; return '!';);

【讨论】:

请注意,String.replace 中的函数回调是 Javascript 1.3 功能 @Alnitak - 这是个问题吗?快速检查显示它于 1998 年发布,并在 IE 4 中实现! en.wikipedia.org/wiki/JavaScript#Versions 不是问题,只是谷歌(w3schools)最常返回的Javascript参考页面没有提及。 @Kobi,您的“单程”解决方案通常不起作用,我已经添加了答案。 @Kobi 第二种方法如何滥用replace 回调?【参考方案2】:

比较前后字符串是检查它是否做了任何事情的最简单方法,String.replace() 没有内在支持。

['==' 可能因错误而无法删除的人为示例]

【讨论】:

为什么要使用=== 来测试两个字符串是否相等? 实际上,'0' == '' 是假的,但0 == '' 是真的——只要你在处理字符串就应该没问题。顺便说一句,=== 是比较字符串中的每个字符,还是检查引用?许多语言使用字符串实习,但我不确定 JavaScript(和所有实现)。如果是这样,这绝对是最好的选择。 @Kobi,在我的人为示例中很好地抓住了 '0' 与 0,但我认为重点仍然是使用 '===' 比较字符串比使用 '== 更可靠'【参考方案3】:

Javascript replace 是设计缺陷。为什么?它与回调中的字符串替换不兼容。

例如:

"ab".replace(/(a)(b)/, "$1$2")
> "ab"

我们要验证替换是否在单次通过中完成。我想象的是这样的:

"ab".replace(/(a)(b)/, "$1$2", function replacing()  console.log('ok'); )
> "ab"

真正的变种:

"ab".replace(/(a)(b)/, function replacing() 
  console.log('ok');
  return "$1$2";
)

> ok
> "$1$2"

但函数replacing 被设计为接收$0, $1, $2, offset, string,我们必须与替换“$1$2”作斗争。解决办法是:

"ab".replace(/(a)(b)/, function replacing() 
  console.log('ok');
  // arguments are $0, $1, ..., offset, string
  return Array.from(arguments).slice(1, -2)
  .reduce(function (pattern, match, index) 
    // '$1' from strings like '$11 $12' shouldn't be replaced.
    return pattern.replace(
      new RegExp("\\$" + (index + 1) + "(?=[^\\d]|$)", "g"),
      match
    );
  , "$1$2");
);

> ok
> "ab"

这个解决方案并不完美。字符串替换本身有自己的 WAT。例如:

"a".replace(/(a)/, "$01")
> "a"

"a".replace(/(a)/, "$001")
> "$001"

如果你想关心兼容性,你必须阅读 spec 并实现它的所有疯狂。

【讨论】:

实际上,那些“WAT”是在spec 中定义的,你不需要为此阅读nodejs源代码 @Zhegan,答案已修复。顺便说一句,这不是一个规范。这是一堆不相容的疯狂。【参考方案4】:

作为一种解决方法,您可以实现自己的回调函数,该函数将设置一个标志并进行替换。 replacereplacement 参数可以接受函数。

【讨论】:

是的,从回调中设置一个标志是一个有趣的想法。谢谢! 据我所知,这是唯一不涉及多次搜索字符串的答案。但显然 JS 开发者并不关心性能。【参考方案5】:

如果您的替换与搜索到的文本长度不同,您可以检查前后字符串的长度。我知道,这是部分响应,仅对问题的一个子集有效。

您可以进行搜索。如果搜索成功,则对从找到的索引开始的子字符串进行替换,然后重新组合字符串。这可能会更慢,因为您生成的是 3 个字符串而不是 2 个。

var test = "Hellllo";
var index = test.search(/ll/);

if (index >= 0) 
    test = test.substr(0, index - 1) + test.substr(index).replace(/ll/g, "tt");


alert(test);

【讨论】:

【参考方案6】:

虽然这需要多次操作,但使用 .test() 可能就足够了:

const regex = /foo/;
const yourString = 'foo bar';

if (regex.test(yourString)) 
  console.log('yourString contains regex');
  // Go ahead and do whatever else you'd like.

The test() method executes a search for a match between a regular expression and a specified string. Returns true or false.

【讨论】:

本题专门要求单次操作,test表示还是需要做替换。 海事组织的最佳选择【参考方案7】:

使用indexOf,您可以检查一个字符串是否包含另一个字符串。 看来您可能想使用它。

【讨论】:

您能详细说明一下吗?您是否建议使用indexOf 将原始结果与replace 的结果进行比较? 我建议在替换之前先做一个indexOf。如果indexOf 返回真,那么你就会知道替换会做任何事情。 问题是indexOf不支持正则表达式 但请不要。如果效率是目标,那么在事后进行匹配后替换肯定会比'==='慢。 @AInitak,实际上search 如果正则表达式简单且足够长,则可能比比较更快。【参考方案8】:

看看 string.match() 或 string.search()

【讨论】:

你是否建议在replace 之前做一个match 以知道后者是否会做任何事情? 不,因为这意味着针对正则表达式解析字符串两次。只需在后面使用 '===' - 如果两个字符串相同,这是最快的比较。

以上是关于如何知道 JavaScript string.replace() 是不是做了啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 JavaScript 对象的所有属性值(不知道键)?

如何知道浏览器选项卡是不是已经使用 Javascript 打开?

如何知道滚动到元素是在 Javascript 中完成的?

如何知道何时从控制台调用 JavaScript 函数? [复制]

如果我不知道名称,如何访问 javascript 对象的属性?

JavaScript 中的反向 while 循环如何知道何时停止?