我正在尝试做类似的事情,但无法让它发挥作用。
How to split a comma separated String while ignoring escaped commas?
我试图解决这个问题,但似乎无法做到这一点。
我想将字符串拆分为:
,而不是转义的字符\\:
(我的逃避字符是双斜线)
给出:dtet:du\\,eduh ei\\:di:e,j
预期结果:["dtet"] ["du\\,eduh ei\\:di][e,j"]
正则表达式链接: https://regex101.com/r/12j6er/1/
答案 0 :(得分:2)
这是一个有点冗长的方法。但适合你。 JavaScript正则表达式不支持lookbehinds。但是你可以通过简单地反转原始字符串并使用lookahead分割字符串来实现。然后反转数组和其中的所有字符串,你就会得到你的结果。
function reverse(s) {
var o = '';
for (var i = s.length - 1; i >= 0; i--)
o += s[i];
return o;
}
var str = "dtet:du\\,eduh ei\\:di:e,j";
var res = reverse(str);
var result = res.split(/:(?!\\)/g);
result = result.reverse();
for(var i = 0; i < result.length; i++){
result[i] = reverse(result[i]);
}
console.log(result);
&#13;
答案 1 :(得分:2)
我可以拿出两个解决方案。一个基于调整数组内容和一个使用正则表达式。
解决方案1:
方法:拆分:
,然后将元素铲入新阵列并将这些元素粘合在一起,应该不分裂。
function splitcolon(input) {
var inparts = input.split(":");
var outparts = [];
var splitwaslegit = true;
inparts.forEach(function(part) {
if (splitwaslegit) {
outparts.push(part);
} else { // the split was not justified, so reverse it by gluing this part to the previous one
outparts[outparts.length-1] += ":" + part;
}
// the next split was legit if this part doesn't end on \\
splitwaslegit = (part.substring(part.length-2) !== "\\\\");
});
return outparts;
}
在chrome中测试:
splitcolon("dtet:du\\\\,eduh ei\\\\:di:e,j")
(3) ["dtet", "du\\,eduh ei\\:di", "e,j"]
注意:
当然也可以使用for
循环或下划线each
代替forEach
解决方案2:
方法:如果有任何char或字符串,你可以100%确定它不会在输入中,那么你可以使用该字符串/字符串作为临时分隔符插入由这样的正则表达式:
var tmpdelim = "\x00"; // must *never* ever occur in input string
var input = "dtet:du\\\\,eduh ei\\\\:di:e,j";
input.replace(/(^.?|[^\\].|.[^\\]):/g, "$1" + tmpdelim).split(tmpdelim);
结果:
(3) ["dtet", "du\\,eduh ei\\:di", "e,j"]
正则表达式/(^.?|[^\\].|.[^\\]):/g
的解释:
/
- 正则表达式的开始
(
- 匹配组1 开始
^.?
- 我们在输入开始时或任何单个字符远离它(逃避需要2)
|
- 或
[^\\].
- 任何不是\
的字符,后跟任何其他字符
|
- 或
.[^\\]
- 除了\
之外的任何其他字符
)
- 匹配组1 停止
:
- 匹配组(不能\\
)必须后跟:
/
- 正则表达式结束
g
- 正则表达式修饰符全局(匹配所有出现,而不仅仅是第一个)
我们用$1 + tmpdelim
替换,所以使用匹配组1 中的任何内容,然后是我们的特殊分隔符(而不是:
),我们可以将其用于分割
奖金解决方案
Manjo Verma的答案是单线:
input.split("").reverse().join("").split(/:(?!\\\\)/).reverse().map(x => x.split("").reverse().join(""));
结果:
(3) ["dtet", "du\\,eduh ei\\:di", "e,j"]
答案 2 :(得分:1)
请参阅下面名为splitOnNonEscapedDelimeter()
的函数,该函数接受要分割的string
和要分割的delimeter
,在本例中为:
。用法在函数onChange()
内。
请注意,您必须将传递给
delimeter
的{{1}}转义为splitOnNonEscapedDelimeter()
,以免将其解释为special character in the regular expression。
function nonEscapedDelimeter(delimeter) {
return new RegExp(String.raw`[^${delimeter}]*?(?:\\\\${delimeter}[^${delimeter}]*?)*(?:${delimeter}|$)`, 'g')
}
function nonEscapedDelimeterAtEnd(delimeter) {
return new RegExp(String.raw`([^\\].|.[^\\]|^.?)${delimeter}$`)
}
function splitOnNonEscapedDelimeter(string, delimeter) {
const reMatch = nonEscapedDelimeter(delimeter)
const reReplace = nonEscapedDelimeterAtEnd(delimeter)
return string.match(reMatch).slice(0, -1).map(section => {
return section.replace(reReplace, '$1')
})
}
function onChange() {
console.log(splitOnNonEscapedDelimeter(i.value, ':'))
}
i.addEventListener('change', onChange)
onChange()
&#13;
<textarea id=i>dtet:du\\,eduh ei\\:di:e,j</textarea>
&#13;
此解决方案使用了ES2015功能String.raw()
和template literals以方便使用,但这些并非必需。如果您的目标平台不包含对这些功能的支持,请参阅上面的相关文档以了解其工作原理并使用a polyfill such as this。
new RegExp(String.raw`[^${delimeter}]*?(?:\\\\${delimeter}[^${delimeter}]*?)*(?:${delimeter}|$)`, 'g')
函数nonEscapedDelimeter()
创建一个几乎完成所需操作的正则表达式,除了一些需要通过一些后处理纠正的怪癖之外。
string.match(reMatch)
正则表达式在String#match()
中使用时,会将字符串拆分为以非转义delimeter
结尾或字符串结尾的部分。这也有在字符串末尾匹配0宽度部分的副作用,因此我们需要
.slice(0, -1)
在后期处理中删除该匹配。
new RegExp(String.raw`([^\\].|.[^\\]|^.?)${delimeter}$`)
...
.map(section => {
return section.replace(reReplace, '')
})
由于每个部分现在以delimeter
结尾,但最后一部分(在字符串末尾结束),我们需要.map()
匹配数组并删除非-escaped delimeter
(因此nonEscapedDelimeterAtEnd()
如此复杂),如果它在那里。