如何替换字符串中所有但第一次出现的模式

Posted

技术标签:

【中文标题】如何替换字符串中所有但第一次出现的模式【英文标题】:How to replace all BUT the first occurrence of a pattern in string 【发布时间】:2011-12-19 02:04:40 【问题描述】:

快速问题:我的模式是一个 svg 字符串,它看起来像 l 5 0 l 0 10 l -5 0 l 0 -10 要与参考进行一些单元测试比较,我需要抛弃除第一个 l 之外的所有内容,我知道我可以将它们全部抛弃并放一个 'l ' 提前,或者我可以使用子字符串。但我想知道这是否有一个 javascript 正则表达式成语?

【问题讨论】:

第一个 l 总是在字符串的开头吗? 我知道你说过你不想要这个,但是直到第一个空格的子字符串似乎最容易阅读和维护。 @Mark 是这个用例,它甚至是“l”,但这也适用于负前瞻。 @Randy 是的,我知道,但我想加深对正则表达式的了解。您关于可读性和可维护性的观点值得考虑。我将从评论开始。 【参考方案1】:

您可以尝试否定前瞻,避免字符串的开头:

/(?!^)l/g

看是否在线:jsfiddle

【讨论】:

我正在尝试修改它以适用于出现的第一个“-”字符,但我遇到了非常困难的时期:(。感谢任何帮助。提前致谢。 如何将它与变量一起使用? @GrantRobertSmith 我知道这已经很晚了,但我提供的答案涵盖了我认为您正在寻找的内容。 这仅在第一个 l 也位于字符串开头时才有效。【参考方案2】:

除了第一个模式匹配之外,没有 JS RegExp 可以替换所有内容。但是,您可以通过将函数作为第二个参数传递给 replacemethod 来实现此行为。

var regexp = /(foo bar )(red)/g; //Example
var string = "somethingfoo bar red  foo bar red red pink   foo bar red red";
var first = true;

//The arguments of the function are similar to $0 $1 $2 $3 etc
var fn_replaceBy = function(match, group1, group2) //group in accordance with RE
    if (first) 
        first = false;
        return match;
    
    // Else, deal with RegExp, for example:
    return group1 + group2.toUpperCase();

string = string.replace(regexp, fn_replaceBy);
//equals string = "something foo bar red  foo bar RED red pink   foo bar RED red"

函数 (fn_replaceBy) 为每个匹配执行。在第一次匹配时,该函数立即返回匹配的字符串(没有任何反应),并设置一个标志。 每隔一个匹配项将根据函数中描述的逻辑进行替换:通常,您使用$0 $1 $2 等来引用组。在 fn_replaceBy 中,函数参数等于:第一个参数 = $0,第二个参数 = $1,等等。

匹配的子字符串将被函数fn_replaceBy的返回值替换。使用函数作为replace 的第二个参数允许非常强大的应用程序,例如intelligent html parser。

另见:MDN: String.replace > Specifying a function as a parameter

【讨论】:

我不相信“智能 HTML 解析器”不会链接到“使用正则表达式解析 HTML”的答案,哈哈。但非常好的答案,这正是我所需要的。 :)【参考方案3】:

这不是最漂亮的解决方案,但您可以用任意的东西(如占位符)替换第一次出现并用链替换来完成其余的逻辑:

'-98324792u4234jkdfhk.sj.dh-f01' // construct valid float
    .replace(/[^\d\.-]/g, '') // first, remove all characters that aren't common
    .replace(/(?!^)-/g, '') // replace negative characters that aren't in beginning
    .replace('.', '%FD%') // replace first occurrence of decimal point (placeholder)
    .replace(/\./g, '') // now replace all but first occurrence (refer to above)
    .replace(/%FD%(0+)?$/, '') // remove placeholder if not necessary at end of string
    .replace('%FD%', '.') // otherwise, replace placeholder with period

生产:

-983247924234.01

这只是扩展了任何人在寻找一个不能依赖于第一个匹配/出现是字符串中的第一个字符的示例的接受答案。

【讨论】:

【参考方案4】:
 "l 5 0 l 0 10 l -5 0 l 0 -10".replace(/^\s+/, '').replace(/\s+l/g, '')

确保第一个'l' 前面没有空格,并删除后面跟'l' 的任何空格。

【讨论】:

【参考方案5】:

这样的?

"l 5 0 l 0 10 l -5 0 l 0 -10".replace(/[^^]l/g, '')

【讨论】:

虽然这在这种情况下确实有效,但^ 不代表字符类中的文字字符吗? [^^] 匹配除'^' 之外的任何字符。它在您需要的输入开头以外的任何点都不匹配零字符。 (!/[^^]/.test('^') && /[^^]/.test('x')) === true【参考方案6】:

我在https://www.regextester.com/99881 找到了这个解决方案,使用了lookbehind 模式:

/(?<=(.*l.*))l/g

或者更一般的

/(?<=(.*MYSTRING.*))MYSTRING/g

其中MYSTRING 是您要删除的内容。

(顺便说一句,这也可能是一个有用的字符串,用于删除电子邮件主题字符串中除第一次出现的“Re:”之外的所有内容。)

【讨论】:

所有正则表达式风格不支持可变长度后视。在 Javascript 中,并非所有浏览器都支持lookbehind。

以上是关于如何替换字符串中所有但第一次出现的模式的主要内容,如果未能解决你的问题,请参考以下文章

如何替换 JavaScript 中所有出现的字符串

如何替换 JavaScript 中所有出现的字符串

如何替换 JavaScript 中所有出现的字符串

如何替换 JavaScript 中所有出现的字符串

如何替换 JavaScript 中所有出现的字符串

如何替换 JavaScript 中所有出现的字符串