仅在指定字符的第一个实例上拆分字符串
Posted
技术标签:
【中文标题】仅在指定字符的第一个实例上拆分字符串【英文标题】:split string only on first instance of specified character 【发布时间】:2011-06-04 05:05:07 【问题描述】:在我的代码中,我根据_
拆分了一个字符串并获取数组中的第二项。
var element = $(this).attr('class');
var field = element.split('_')[1];
接受good_luck
并为我提供luck
。效果很好!
但是,现在我有一个看起来像 good_luck_buddy
的类。如何让我的 javascript 忽略第二个 _
并给我 luck_buddy
?
我在 c# *** 答案中找到了这个var field = element.split(new char [] '_', 2);
,但它不起作用。我在 jsFiddle 上试了一下...
【问题讨论】:
【参考方案1】:使用capturing parentheses:
"good_luck_buddy".split(/_(.+)/)[1]
"luck_buddy"
它们被定义为
如果
separator
包含捕获括号,则匹配结果为 在数组中返回。
所以在这种情况下,我们希望在_.+
处进行拆分(即拆分分隔符是一个以_
开头的子字符串)但也让结果包含我们的分隔符的某些部分(即_
之后的所有内容。
在这个例子中,我们的分隔符(匹配_(.+)
)是_luck_buddy
,捕获的组(在分隔符内)是lucky_buddy
。如果没有捕获括号,luck_buddy
(匹配 .+
)将不会包含在结果数组中,因为简单的split
就是这种情况,结果中不包含分隔符。
【讨论】:
你甚至不需要 (?),只需使用 /_(.+)/ 在第一个 _ 之后再捕获 1 个字符 非常优雅。奇迹般有效。谢谢。 要明确一点,这个解决方案之所以有效,是因为第一个_
之后的所有内容都在捕获组中匹配,并因此被添加到令牌列表中。
任何人都知道为什么我会得到一个额外的空字符串元素:in:"Aspect Ratio: 16:9".split(/:(.+)/)
out:["Aspect Ratio", " 16:9", ""]
@katylavallee - 这可能会有所帮助:***.com/questions/12836062/… 由于分隔符是 ": 16:9"
,因此分隔符后面没有任何内容,因此在末尾创建了空字符串。【参考方案2】:
你需要什么正则表达式和数组?
myString = myString.substring(myString.indexOf('_')+1)
var myString= "hello_there_how_are_you"
myString = myString.substring(myString.indexOf('_')+1)
console.log(myString)
【讨论】:
字符串!==字符串。 javascript 区分大小写。 我认为这是最好的答案。也可以在第二个_
之后获取字符串:myString.substring( myString.indexOf('_', myString().indexOf('_') + 1) + 1 )
答案输出字符串的第二部分。如果你也想要第一部分怎么办?使用var str = "good_luck_buddy", res = str.split(/_(.+)/);
您可以获得所有部分:console.log(res[0]); console.log(res[1]);
@PeterLeger let split = [ string.substring(0, string.indexOf(options.divider)), string.substring(string.indexOf(options.divider) + 1) ]
你有它。还支持可变针
这是天才!【参考方案3】:
我不惜一切代价避免使用 RegExp。这是您可以做的另一件事:
"good_luck_buddy".split('_').slice(1).join('_')
【讨论】:
害怕RegExp的人永远不会被告知RegExp有多棒。你需要自己找到门。一旦你到了那里,你就永远不会回头。几年后再问我,你会告诉我它有多棒。 @yonas 服用红色药丸! @yonas 是的,吃红色药丸!它会让你的生活更快,即使是短字符串:jsperf.com/split-by-first-colon 哈!我在 4 多年前写了这个评论。我现在绝对支持 RegExp! :) @yonas 你最好不要。当您需要它时,RegExp 非常棒。不是这里的情况。检查更新的测试:jsperf.com/split-by-first-colon/2【参考方案4】:在解构赋值的帮助下,它可以更具可读性:
let [first, ...rest] = "good_luck_buddy".split('_')
rest = rest.join('_')
【讨论】:
ES6 的最佳答案 嗯,完美程度取决于rest
有多少分隔符。
超级好用且非常灵活。【参考方案5】:
获取字符串中第一个键和剩余部分的简单 ES6 方法是:
const [key, ...rest] = "good_luck_buddy".split('_')
const value = rest.join('_')
console.log(key, value) // good, luck_buddy
【讨论】:
【参考方案6】:现在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"]
【讨论】:
这里也一样。似乎 php 正在分裂为“第一”和“休息”。【参考方案7】:用唯一的占位符替换第一个实例,然后从那里拆分。
"good_luck_buddy".replace(/\_/,'&').split('&')
["good","luck_buddy"]
这在需要拆分两边时更有用。
【讨论】:
这对字符串施加了不必要的约束。 当上述所有答案都不起作用时,这个答案对我有用。 @YanFoto 你的意思是使用'&'?可以是任何东西。 @sebjwallace 无论您选择什么,这意味着您不能在字符串中包含该字符。例如。我认为“fish&chips_are_great”给出了[fish,chips,are_great]。 @Joe 你可以使用任何东西来代替'&'——这只是一个例子。如果需要,您可以将第一次出现的 _ 替换为 ¬。因此,“fish&chips_are_great”会将第一次出现的 _ 替换为 ¬ 以给出“fish&chips¬are_great”,然后除以 ¬ 以获得 ["fish&chips","are_great"]【参考方案8】:这个解决方案对我有用
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"
【讨论】:
但是,如果拆分器的字符数超过 1 个,这将不起作用。【参考方案9】:您可以使用如下正则表达式:
var arr = element.split(/_(.*)/)
您可以使用指定拆分限制的第二个参数。
IE:
var field = element.split('_', 1)[1];
【讨论】:
只指定返回多少拆分项,不指定拆分多少次。'good_luck_buddy'.split('_', 1);
只返回 ['good']
感谢对此做出了假设。更新帖子以使用正则表达式。
(:?.*)
应该是非捕获组吗?如果是这样,它应该是(?:.*)
,但如果你更正它,你会发现它不再起作用了。 (:?.*)
匹配可选的:
,后跟零个或多个任意字符。该解决方案最终以与@MarkF 相同的原因起作用:第一个_
之后的所有内容都被添加到令牌列表中,因为它在捕获组中匹配。 (此外,g
修饰符在用于拆分正则表达式时无效。)
谢谢,没意识到。更新了正则表达式并尝试了几个场景......
它在 ie8 中不起作用,我切换回 indexOf 和 substring【参考方案10】:
我需要字符串的两个部分,所以,regex lookbehind 帮我解决这个问题。
const full_name = 'Maria do Bairro';
const [first_name, last_name] = full_name.split(/(?<=^[^ ]+) /);
console.log(first_name);
console.log(last_name);
【讨论】:
最佳答案在这里!【参考方案11】:非正则表达式解决方案
我跑了一些benchmarks,这个解决方案大获全胜: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
或 RegExp
s 的其他解决方案对性能造成了很大影响,并且速度慢了大约 2 个数量级。在split
的结果上使用join
当然会增加额外的性能损失。
为什么它们变慢了?每当必须创建新对象或数组时,JS 都必须从操作系统请求一块内存。这个过程很慢。
以下是一些通用指南,以防您追求基准:
为对象
或数组 []
(就像 split
创建的那样)分配新的动态内存会大大降低性能。
RegExp
搜索更复杂,因此比字符串搜索要慢。
如果您已经有一个数组,解构数组的速度与显式索引它们的速度差不多,而且看起来很棒。
在第一个实例之外删除
这是一个解决方案,它可以分割到并包括第 n 个实例。它不是那么快,但在 OP 的问题上,gobble(element, '_', 1)
仍然比 RegExp
或 split
解决方案快 > 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)
将像此答案中的第一个解决方案一样删除前缀。
-
测试是在 macOSX 10.14 上的 Chrome 70.0.3538.110 中运行的。
【讨论】:
来吧……现在是 2019 年……人们真的还在做微基准测试吗? 我同意。尽管微基准测试有点有趣,但您应该依赖编译器或翻译器进行优化。谁知道呢。 Mb 有人阅读本文正在构建编译器或使用 ejs / 嵌入式并且不能使用正则表达式。但是,对于我的具体情况,这看起来比正则表达式更好。 (我会删除“最快的解决方案”) 我毫不怀疑 JIT 编译器会有所帮助。然而,这些测试表明,使用简单的字符串函数仍然可以提高性能(并且避免使用复杂、容易出错的正则表达式)。 与多个嵌套循环、分支和索引跟踪相比,一个简单的正则表达式到底有多复杂?宝贝,遇见洗澡水。你们将一起去旅行。 这是我一直在寻找的单线。至于正则表达式基准测试,您是否尝试将正则表达式本身移出测试循环进入(模块)全局变量?这通常会有所帮助,因此差异不会那么令人印象深刻。至于人们对事物进行微基准测试,很高兴拥有一个有效的、经过良好测试的快速版本的 split-with-a-limit,Javascript 明显缺乏,但其他语言通常在它们的标准库中。有时这些东西比简单更重要。【参考方案12】:不幸的是,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('_');
【讨论】:
我看到拆分功能没有帮助,但使用正则表达式似乎可以实现这一点。它应该指定您在本机地引用 Split 函数本身。 有趣,这个解决方案将问题提炼成一个更具可读性/可管理性的解决方案。在我将全名转换为第一个和最后一个的情况下(是的,我们的要求强制了这个逻辑)这个解决方案效果最好,并且比其他解决方案更具可读性。谢谢 这不再是真的 :)【参考方案13】:使用字符串replace()
方法和regex:
var result = "good_luck_buddy".replace(/.*?_/, "");
console.log(result);
此正则表达式匹配第一个 _
之前的 0 个或多个字符,以及 _
本身。然后将匹配项替换为空字符串。
【讨论】:
这里的document.body.innerhtml
部分完全没用。
@VictorSchröder 如果没有document.body.innerHTML
,您希望如何看到 sn-p 的输出?
document.body
取决于要存在的 DOM,它不适用于纯 JavaScript 环境。 console.log
足以达到此目的,或者干脆将结果留在变量中以供检查。
@VictorSchröder 我认为这不会造成太多混乱,但我还是编辑了。【参考方案14】:
这是一个可以解决问题的正则表达式。
'good_luck_buddy' . split(/^.*?_/)[1]
首先它强制匹配从 以“^”开头。然后它匹配任何数字 不是'_'的字符,换句话说 第一个“_”之前的所有字符。
“?”表示最少的字符数 使整个模式匹配的是 由 '.*?' 匹配因为它被遵循 通过'_',然后将其包含在匹配中 作为它的最后一个字符。
因此这个 split() 使用了这样的匹配 部分作为它的“分离器”并将其从 结果。所以它删除了一切 直到并包括第一个 '_' 和 给你剩下的作为第二个元素 结果。第一个元素是“”代表 匹配部分之前的部分。它是 "" 因为匹配从头开始。
还有其他正则表达式可以作为 很像 Chandu 给出的 /_(.*)/ 在之前的回答中。
/^.*?_/ 有你的好处 可以理解它的作用 必须了解特殊角色 使用 replace() 捕获组。
【讨论】:
【参考方案15】:Mark F 的解决方案很棒,但旧浏览器不支持它。 Kennebec 的解决方案很棒,旧浏览器支持但不支持正则表达式。
因此,如果您正在寻找一种仅将字符串拆分一次的解决方案,该解决方案受旧浏览器支持并支持正则表达式,这是我的解决方案:
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]);
【讨论】:
【参考方案16】:对于像我这样不习惯正则表达式的初学者来说,这个变通解决方案很有效:
var field = "Good_Luck_Buddy";
var newString = field.slice( field.indexOf("_")+1 );
slice() 方法提取字符串的一部分并返回一个新字符串,indexOf() 方法返回字符串中指定值第一次出现的位置。
【讨论】:
这不是一种解决方法,而是一种正确的方法;)【参考方案17】:如果您正在寻找更现代的方法:
let raw = "good_luck_buddy"
raw.split("_")
.filter((part, index) => index !== 0)
.join("_")
【讨论】:
【参考方案18】:这应该很快
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])
【讨论】:
嗯,我一直在找这个【参考方案19】:这在 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)
【讨论】:
以上是关于仅在指定字符的第一个实例上拆分字符串的主要内容,如果未能解决你的问题,请参考以下文章