Javascript 以及 regex: 分割字符串并保留分隔符

我有一个字符串:

var string = "aaaaaa
† bbbb
‡ cccc"

我想用分隔符
分割这个字符串,后面跟着一个特殊字符。

要做到这一点,我使用这个:

string.split(/
&#?[a-zA-Z0-9]+;/g);

我得到了我需要的东西,除了我丢失了分隔符。 下面是示例:http://jsfiddle.net/JwrZ6/1/

如何保留分隔符?

136034 次浏览

使用(积极的)超前使正则表达式断言特殊字符存在,但实际上并不匹配它:

string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g);

看看它的实际应用:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc";
console.log(string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g));

如果将分隔符括在parantheses中,它将是返回数组的一部分。

string.split(/(<br \/>&#?[a-zA-Z0-9]+);/g);
// returns ["aaaaaa", "<br />&dagger;", "bbbb", "<br />&Dagger;", "cccc"]

根据你想保留的部分来改变你匹配的子组

string.split(/(<br \/>)&#?[a-zA-Z0-9]+;/g);
// returns ["aaaaaa", "<br />", "bbbb", "<br />", "cccc"]
你可以通过忽略字母的大小写来改进表达式 string.split (/ (), # ? [a-z0-9] +, / gi); < / p >

你可以像这样匹配预定义的组:\d等于[0-9]\w等于[a-zA-Z0-9_]。这意味着表达式可以是这样的。

string.split(/<br \/>(&#?[a-z\d]+;)/gi);

有一个很好的正则表达式参考JavaScriptKit

扩展函数将字符串与子字符串或RegEx分开,分隔符根据第二个参数放在前面或后面。

    String.prototype.splitKeep = function (splitter, ahead) {
var self = this;
var result = [];
if (splitter != '') {
var matches = [];
// Getting mached value and its index
var replaceName = splitter instanceof RegExp ? "replace" : "replaceAll";
var r = self[replaceName](splitter, function (m, i, e) {
matches.push({ value: m, index: i });
return getSubst(m);
});
// Finds split substrings
var lastIndex = 0;
for (var i = 0; i < matches.length; i++) {
var m = matches[i];
var nextIndex = ahead == true ? m.index : m.index + m.value.length;
if (nextIndex != lastIndex) {
var part = self.substring(lastIndex, nextIndex);
result.push(part);
lastIndex = nextIndex;
}
};
if (lastIndex < self.length) {
var part = self.substring(lastIndex, self.length);
result.push(part);
};
// Substitution of matched string
function getSubst(value) {
var substChar = value[0] == '0' ? '1' : '0';
var subst = '';
for (var i = 0; i < value.length; i++) {
subst += substChar;
}
return subst;
};
}
else {
result.add(self);
};
return result;
};

测试:

    test('splitKeep', function () {
// String
deepEqual("1231451".splitKeep('1'), ["1", "231", "451"]);
deepEqual("123145".splitKeep('1', true), ["123", "145"]);
deepEqual("1231451".splitKeep('1', true), ["123", "145", "1"]);
deepEqual("hello man how are you!".splitKeep(' '), ["hello ", "man ", "how ", "are ", "you!"]);
deepEqual("hello man how are you!".splitKeep(' ', true), ["hello", " man", " how", " are", " you!"]);
// Regex
deepEqual("mhellommhellommmhello".splitKeep(/m+/g), ["m", "hellomm", "hellommm", "hello"]);
deepEqual("mhellommhellommmhello".splitKeep(/m+/g, true), ["mhello", "mmhello", "mmmhello"]);
});

我遇到了类似但略有不同的问题。无论如何,这里有三种不同场景的示例,用于说明在何处保存分隔符。

"1、2、3".split("、") == ["1", "2", "3"]
"1、2、3".split(/(、)/g) == ["1", "、", "2", "、", "3"]
"1、2、3".split(/(?=、)/g) == ["1", "、2", "、3"]
"1、2、3".split(/(?!、)/g) == ["1、", "2、", "3"]
"1、2、3".split(/(.*?、)/g) == ["", "1、", "", "2、", "3"]

警告:第四个只适用于拆分单个字符。ConnorsFan呈现另一种选择:

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);

我一直在用这个:

String.prototype.splitBy = function (delimiter) {
var
delimiterPATTERN = '(' + delimiter + ')',
delimiterRE = new RegExp(delimiterPATTERN, 'g');


return this.split(delimiterRE).reduce((chunks, item) => {
if (item.match(delimiterRE)){
chunks.push(item)
} else {
chunks[chunks.length - 1] += item
};
return chunks
}, [])
}

除了你不应该混淆String.prototype,所以这里是一个函数版本:

var splitBy = function (text, delimiter) {
var
delimiterPATTERN = '(' + delimiter + ')',
delimiterRE = new RegExp(delimiterPATTERN, 'g');


return text.split(delimiterRE).reduce(function(chunks, item){
if (item.match(delimiterRE)){
chunks.push(item)
} else {
chunks[chunks.length - 1] += item
};
return chunks
}, [])
}

你可以这样做:

var haystack = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"
var needle =  '<br \/>&#?[a-zA-Z0-9]+;';
var result = splitBy(haystack , needle)
console.log( JSON.stringify( result, null, 2) )

你会得到:

[
"<br />&dagger; bbbb",
"<br />&Dagger; cccc"
]

JavaScript分割正则表达式保留分隔符

在正则表达式中使用(?=pattern)前视模式 示例< / p >

var string = '500x500-11*90~1+1';
string = string.replace(/(?=[$-/:-?{-~!"^_`\[\]])/gi, ",");
string = string.split(",");

这将得到以下结果。

[ '500x500', '-11', '*90', '~1', '+1' ]

还可以直接拆分吗

string = string.split(/(?=[$-/:-?{-~!"^_`\[\]])/gi);

给出相同的结果

[ '500x500', '-11', '*90', '~1', '+1' ]

我对jichi的回答做了修改,并把它放在一个支持多字母的函数中。

String.prototype.splitAndKeep = function(separator, method='seperate'){
var str = this;
if(method == 'seperate'){
str = str.split(new RegExp(`(${separator})`, 'g'));
}else if(method == 'infront'){
str = str.split(new RegExp(`(?=${separator})`, 'g'));
}else if(method == 'behind'){
str = str.split(new RegExp(`(.*?${separator})`, 'g'));
str = str.filter(function(el){return el !== "";});
}
return str;
};

jichi的答案第三种方法在这个函数中不起作用,所以我采用了第四种方法,并删除了空白区域以获得相同的结果。

< p >编辑: 第二个方法,除了一个数组来拆分char1或char2

String.prototype.splitAndKeep = function(separator, method='seperate'){
var str = this;
function splitAndKeep(str, separator, method='seperate'){
if(method == 'seperate'){
str = str.split(new RegExp(`(${separator})`, 'g'));
}else if(method == 'infront'){
str = str.split(new RegExp(`(?=${separator})`, 'g'));
}else if(method == 'behind'){
str = str.split(new RegExp(`(.*?${separator})`, 'g'));
str = str.filter(function(el){return el !== "";});
}
return str;
}
if(Array.isArray(separator)){
var parts = splitAndKeep(str, separator[0], method);
for(var i = 1; i < separator.length; i++){
var partsTemp = parts;
parts = [];
for(var p = 0; p < partsTemp.length; p++){
parts = parts.concat(splitAndKeep(partsTemp[p], separator[i], method));
}
}
return parts;
}else{
return splitAndKeep(str, separator, method);
}
};

用法:

str = "first1-second2-third3-last";


str.splitAndKeep(["1", "2", "3"]) == ["first", "1", "-second", "2", "-third", "3", "-last"];


str.splitAndKeep("-") == ["first1", "-", "second2", "-", "third3", "-", "last"];

我还想到了这个解。不需要正则表达式,非常易读。

const str = "hello world what a great day today balbla"
const separatorIndex = str.indexOf("great")
const parsedString = str.slice(separatorIndex)


console.log(parsedString)

如果你对拆分模式进行分组,它的匹配将被保留在输出中,这是通过设计的:

如果separator是一个捕获括号的正则表达式,则 每次分隔符匹配时,结果(包括任何未定义的 捕获括号的结果)拼接到输出中 数组。< / p >

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split#description

除非您的搜索模式使用前瞻性或全局标志,否则您不需要这些标志。

const str = `How much wood would a woodchuck chuck, if a woodchuck could chuck wood?`


const result = str.split(/(\s+)/);
console.log(result);


// We can verify the result
const isSame = result.join('') === str;
console.log({ isSame });

您可以使用多个组。你可以尽情发挥你的创造力,小组之外的内容将被删除:

const str = `How much wood would a woodchuck chuck, if a woodchuck could chuck wood?`


const result = str.split(/(\s+)(\w{1,2})\w+/);
console.log(result, result.join(''));

现有的大多数答案都在2018年JavaScript引入向后插入断言之前。您没有指定希望如何在结果中包含分隔符。一个典型的用例是用标点符号([.?!])分隔的句子,人们希望在结果字符串的末尾包含分隔符。这对应于已接受答案中的第四种情况,但如此处所述,该解决方案仅适用于单个字符。任何带有分隔符的字符串都可以通过后视断言形成:

'It is. Is it? It is!'.split(/(?<=[.?!])/)
/* [ 'It is.', ' Is it?', ' It is!' ] */

我知道这有点晚了,但你也可以使用lookarounds

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc";
var array = string.split(/(?<=<br \/>)/);
console.log(array);