只在指定字符的第一个实例上拆分字符串

在我的代码中,我基于_分割了一个字符串,并获取数组中的第二项。

var element = $(this).attr('class');
var field = element.split('_')[1];

获取good_luck并为我提供luck。工作好了!

但是,现在我有了一个类似good_luck_buddy的类。我如何让我的javascript忽略第二个_,给我luck_buddy?

我发现这个var field = element.split(new char [] {'_'}, 2);在c# stackoverflow的答案,但它不工作。我尝试在jsFiddle…

342307 次浏览

你可以像这样使用正则表达式:

var arr = element.split(/_(.*)/)
您可以使用第二个参数,它指定分割的限制。 即: Var字段=元素。分割(' _ ',1)[1];

不幸的是,Javascript的String.split没有办法限制分割的实际数量。它有第二个参数,用于指定返回多少实际拆分项,这在您的示例中没有用处。解决方案是分割字符串,将第一项移开,然后重新连接其余的项:

var element = $(this).attr('class');
var parts = element.split('_');


parts.shift(); // removes the first item from the array
var field = parts.join('_');

使用捕捉括号:

'good_luck_buddy'.split(/_(.*)/s)
['good', 'luck_buddy', ''] // ignore the third element

它们被定义为

如果separator包含捕获括号,匹配的结果将在数组中返回。

因此,在本例中,我们希望在_.*处分割(即分割分隔符是以_开头的子字符串)但也让结果包含分隔符的一部分(即一切_之后)。

在这个例子中,我们的分隔符(匹配_(.*))是_luck_buddy,捕获的组(在分隔符内)是lucky_buddy。如果没有捕获括号,luck_buddy(匹配.*)将不会包含在结果数组中,因为简单的split的情况下,分隔符不包含在结果中。

我们使用s正则表达式标志来使.匹配换行符(\n),否则它只会分割到第一个换行符。

你需要正则表达式和数组做什么?

myString = myString.substring(myString.indexOf('_')+1)

var myString= "hello_there_how_are_you"
myString = myString.substring(myString.indexOf('_')+1)
console.log(myString)

我不惜一切代价避免RegExp。还有一件事你可以做:

"good_luck_buddy".split('_').slice(1).join('_')

Mark F的解决方案很棒,但旧的浏览器不支持。Kennebec的解决方案很棒,老浏览器也支持,但不支持regex。

所以,如果你正在寻找一个解决方案,只分割你的字符串一次,这是由旧浏览器支持和支持regex,这是我的解决方案:

.
String.prototype.splitOnce = function(regex)
{
var match = this.match(regex);
if(match)
{
var match_i = this.indexOf(match[0]);
        

return [this.substring(0, match_i),
this.substring(match_i + match[0].length)];
}
else
{ return [this, ""]; }
}


var str = "something/////another thing///again";


alert(str.splitOnce(/\/+/)[1]);

对于像我这样不习惯正则表达式的初学者来说,这个解决方案是有效的:

   var field = "Good_Luck_Buddy";
var newString = field.slice( field.indexOf("_")+1 );

slice()方法提取字符串的一部分并返回一个新字符串,indexOf()方法返回字符串中指定值第一次出现的位置。

这适用于我的Chrome + FF:

"foo=bar=beer".split(/^[^=]+=/)[1] // "bar=beer"
"foo==".split(/^[^=]+=/)[1] // "="
"foo=".split(/^[^=]+=/)[1] // ""
"foo".split(/^[^=]+=/)[1] // undefined

如果你也需要钥匙,试试这个:

"foo=bar=beer".split(/^([^=]+)=/) // Array [ "", "foo", "bar=beer" ]
"foo==".split(/^([^=]+)=/) // [ "", "foo", "=" ]
"foo=".split(/^([^=]+)=/) // [ "", "foo", "" ]
"foo".split(/^([^=]+)=/) // [ "foo" ]


//[0] = ignored (holds the string when there's no =, empty otherwise)
//[1] = hold the key (if any)
//[2] = hold the value (if any)

用唯一的占位符替换第一个实例,然后从那里拆分。

"good_luck_buddy".replace(/\_/,'&').split('&')


["good","luck_buddy"]

当拆分的双方都需要时,这更有用。

我需要字符串的两个部分,所以,regex lookbehind帮助我这个。

const full_name = 'Maria do Bairro';
const [first_name, last_name] = full_name.split(/(?<=^[^ ]+) /);
console.log(first_name);
console.log(last_name);

使用带有正则表达式的字符串replace()方法:

var result = "good_luck_buddy".replace(/.*?_/, "");
console.log(result);

这个正则表达式匹配第一个_之前的0个或更多字符,以及_本身。然后将匹配项替换为空字符串。

这里有一个RegExp可以完成这个任务。

'good_luck_buddy' . split(/^.*?_/)[1]

首先,它强制匹配从 从“^”开始。然后它匹配任何数字 换句话说,不是'_'的字符

.

.

. < p >”?'表示最小字符数 使整个模式匹配的是 由'.*?“因为它是被遵循的 通过'_',然后包含在匹配中 作为最后一个角色。< / p > 因此split()使用这样的匹配 部分作为它的“分配器”,并将其从 结果。所以它删除了所有东西 直到并包括第一个“_”和 剩下的作为第二元素 结果。第一个元素是“”表示 匹配部分之前的部分。它是

. ""因为匹配从头开始

有其他regexp作为 很像Chandu给出的/_(.*)/ 在之前的回答中。< / p > < p > / ^ * ?_/对你有好处 能理解它没有什么吗 必须了解这个特殊角色 捕获组使用replace().

Non-regex解决方案

我运行了一些基准,这个解决方案赢得了巨大的胜利:1

str.slice(str.indexOf(delim) + delim.length)


// as function
function gobbleStart(str, delim) {
return str.slice(str.indexOf(delim) + delim.length);
}


// as polyfill
String.prototype.gobbleStart = function(delim) {
return this.slice(this.indexOf(delim) + delim.length);
};

与其他解决方案的性能比较

唯一接近的竞争者是同一行代码,除了使用substr而不是slice

我尝试的其他涉及split或__abc1的解决方案在性能上受到了很大的打击,大约慢了2 数量级。当然,在split的结果上使用join会增加额外的性能损失。

为什么它们变慢了?每当需要创建一个新对象或数组时,JS都必须向操作系统请求一大块内存。这个过程非常缓慢。

以下是一些通用指南,以防你在追逐基准测试:

  • 为对象{}或数组[]分配新的动态内存(就像split创建的那样)将在性能上付出很大的代价。
  • RegExp搜索更复杂,因此比字符串搜索慢。
  • 如果你已经有一个数组,解构数组和显式索引数组一样快,而且看起来很棒。

从第一个实例移除

下面是一个解决方案,它将分割到并包括第n个实例。它没有那么快,但在OP的问题上,gobble(element, '_', 1)仍然比RegExpsplit解决方案快2倍,并且可以做更多:

/*
`gobble`, given a positive, non-zero `limit`, deletes
characters from the beginning of `haystack` until `needle` has
been encountered and deleted `limit` times or no more instances
of `needle` exist; then it returns what remains. If `limit` is
zero or negative, delete from the beginning only until `-(limit)`
occurrences or less of `needle` remain.
*/
function gobble(haystack, needle, limit = 0) {
let remain = limit;
if (limit <= 0) { // set remain to count of delim - num to leave
let i = 0;
while (i < haystack.length) {
const found = haystack.indexOf(needle, i);
if (found === -1) {
break;
}
remain++;
i = found + needle.length;
}
}


let i = 0;
while (remain > 0) {
const found = haystack.indexOf(needle, i);
if (found === -1) {
break;
}
remain--;
i = found + needle.length;
}
return haystack.slice(i);
}

对于上面的定义,gobble('path/to/file.txt', '/')将给出文件的名称,而gobble('prefix_category_item', '_', 1)将像这个答案中的第一个解决方案一样删除前缀。


  1. 测试在macOSX 10.14上的Chrome 70.0.3538.110中运行。

这个解决方案对我很有效

var str = "good_luck_buddy";
var index = str.indexOf('_');
var arr = [str.slice(0, index), str.slice(index + 1)];


//arr[0] = "good"
//arr[1] = "luck_buddy"

var str = "good_luck_buddy";
var index = str.indexOf('_');
var [first, second] = [str.slice(0, index), str.slice(index + 1)];


//first = "good"
//second = "luck_buddy"

现在String.prototype.split确实允许你限制分割的数量。

str.split([separator[, limit]])

...

限制可选

限制分割次数的非负整数。如果提供,则在指定分隔符的每个出现处拆分字符串,但在数组中已放入限制项时停止。数组中根本不包括任何剩余文本。

如果在到达限制之前到达字符串的末尾,则数组包含的条目可能少于限制。 如果limit为0,则不进行分裂

警告

它可能不会像你期望的那样工作。我希望它只是忽略其余的分隔符,但相反,当它达到限制时,它再次分割剩余的字符串,从返回结果中省略分割后的部分。

let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C"]

我希望:

let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B_C_D_E"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C_D_E"]


在解构赋值的帮助下,它可以更易于阅读:

let [first, ...rest] = "good_luck_buddy".split('_')
rest = rest.join('_')

这应该很快

function splitOnFirst (str, sep) {
const index = str.indexOf(sep);
return index < 0 ? [str] : [str.slice(0, index), str.slice(index + sep.length)];
}


console.log(splitOnFirst('good_luck', '_')[1])
console.log(splitOnFirst('good_luck_buddy', '_')[1])

ES6中获取字符串中第一个键和其余部分的简单方法是:

 const [key, ...rest] = "good_luck_buddy".split('_')
const value = rest.join('_')
console.log(key, value) // good, luck_buddy

如果你正在寻找一种更现代的方式来做这件事:

let raw = "good_luck_buddy"


raw.split("_")
.filter((part, index) => index !== 0)
.join("_")

一个简单的es6一条语句解决方案来获得第一个键和其余部分

let raw = 'good_luck_buddy'


raw.split('_')
.reduce((p, c, i) => i === 0 ? [c] : [p[0], [...p.slice(1), c].join('_')], [])

你也可以使用非贪婪匹配,它只是一个简单的行:

a = "good_luck_buddy"
const [,g,b] = a.match(/(.*?)_(.*)/)
console.log(g,"and also",b)