解析字符串:提取单词和短语 [JavaScript]
-
09-06-2019 - |
题
我需要在以空格分隔的术语列表中支持确切的短语(用引号引起来)。因此,用空格字符分割相应的字符串已经不够了。
例子:
input : 'foo bar "lorem ipsum" baz'
output: ['foo', 'bar', 'lorem ipsum', 'baz']
我想知道这是否可以通过单个正则表达式来实现,而不是执行复杂的解析或拆分和重新连接操作。
任何帮助将不胜感激!
解决方案
var str = 'foo bar "lorem ipsum" baz';
var results = str.match(/("[^"]+"|[^"\s]+)/g);
...返回您要查找的数组。
但请注意:
- 包含边界引号,因此可以使用以下命令删除
replace(/^"([^"]+)"$/,"$1")
关于结果。 - 引号之间的空格将保持不变。所以,如果之间有三个空格
lorem
和ipsum
, ,它们将出现在结果中。您可以通过运行来修复此问题replace(/\s+/," ")
关于结果。 - 如果没有关闭
"
后ipsum
(IE。一个错误引用的短语)你最终会得到:['foo', 'bar', 'lorem', 'ipsum', 'baz']
其他提示
尝试这个:
var input = 'foo bar "lorem ipsum" baz';
var R = /(\w|\s)*\w(?=")|\w+/g;
var output = input.match(R);
output is ["foo", "bar", "lorem ipsum", "baz"]
请注意,lorem ipsum 周围没有额外的双引号
尽管它假设输入在正确的位置有双引号:
var input2 = 'foo bar lorem ipsum" baz'; var output2 = input2.match(R);
var input3 = 'foo bar "lorem ipsum baz'; var output3 = input3.match(R);
output2 is ["foo bar lorem ipsum", "baz"]
output3 is ["foo", "bar", "lorem", "ipsum", "baz"]
并且不会处理转义的双引号(这是一个问题吗?):
var input4 = 'foo b\"ar bar\" \"bar "lorem ipsum" baz';
var output4 = input4.match(R);
output4 is ["foo b", "ar bar", "bar", "lorem ipsum", "baz"]
怎么样,
output = /(".+?"|\w+)/g.exec(input)
然后传递输出以丢失引号。
交替,
output = /"(.+?)"|(\w+)/g.exec(input)
然后进行第 n 次输出以丢失空捕获。
非常感谢您的快速回复!
以下是供后代使用的选项摘要:
var input = 'foo bar "lorem ipsum" baz';
output = input.match(/("[^"]+"|[^"\s]+)/g);
output = input.match(/"[^"]*"|\w+/g);
output = input.match(/("[^"]*")|([^\s"]+)/g)
output = /(".+?"|\w+)/g.exec(input);
output = /"(.+?)"|(\w+)/g.exec(input);
作为记录,这是我想出的令人厌恶的东西:
var input = 'foo bar "lorem ipsum" "dolor sit amet" baz';
var terms = input.split(" ");
var items = [];
var buffer = [];
for(var i = 0; i < terms.length; i++) {
if(terms[i].indexOf('"') != -1) { // outer phrase fragment -- N.B.: assumes quote is either first or last character
if(buffer.length === 0) { // beginning of phrase
//console.log("start:", terms[i]);
buffer.push(terms[i].substr(1));
} else { // end of phrase
//console.log("end:", terms[i]);
buffer.push(terms[i].substr(0, terms[i].length - 1));
items.push(buffer.join(" "));
buffer = [];
}
} else if(buffer.length != 0) { // inner phrase fragment
//console.log("cont'd:", terms[i]);
buffer.push(terms[i]);
} else { // individual term
//console.log("standalone:", terms[i]);
items.push(terms[i]);
}
//console.log(items, "\n", buffer);
}
items = items.concat(buffer);
//console.log(items);
'foo bar "lorem ipsum" baz'.match(/"[^"]*"|\w+/g);
不过,边界引号会被包含在内
一个简单的正则表达式就可以了,但要留下引号。例如
'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g)
output: ['foo', 'bar', '"lorem ipsum"', 'baz']
编辑:被shyamsundar击败,抱歉双重答案
一种易于理解且通用的解决方案。适用于所有分隔符和“连接”字符。还支持长度超过两个单词的“连接”单词......即列出类似
"hello my name is 'jon delaware smith fred' I have a 'long name'"
....
有点像 AC 的答案,但更简洁一点......
function split(input, delimiter, joiner){
var output = [];
var joint = [];
input.split(delimiter).forEach(function(element){
if (joint.length > 0 && element.indexOf(joiner) === element.length - 1)
{
output.push(joint.join(delimiter) + delimiter + element);
joint = [];
}
if (joint.length > 0 || element.indexOf(joiner) === 0)
{
joint.push(element);
}
if (joint.length === 0 && element.indexOf(joiner) !== element.length - 1)
{
output.push(element);
joint = [];
}
});
return output;
}
如果您只是想知道如何自己构建正则表达式,您可能想查看 Expresso (快递链接)。它是学习如何构建正则表达式的好工具,因此您可以了解语法的含义。
当您构建了自己的表达式后,您可以执行 .match
在上面。
这可能是一个很晚的答案,但我有兴趣回答
([\w]+|\"[\w\s]+\")
http://regex101.com/r/dZ1vT6/72
纯 JavaScript 示例
'The rain in "SPAIN stays" mainly in the plain'.match(/[\w]+|\"[\w\s]+\"/g)
输出:
["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"]
ES6 解决方案支持:
- 除内部引号外按空格分割
- 删除引号,但不删除反斜杠转义引号
- 转义引用变成引用
代码:
input.match(/\\?.|^$/g).reduce((p, c) => {
if(c === '"'){
p.quote ^= 1;
}else if(!p.quote && c === ' '){
p.a.push('');
}else{
p.a[p.a.length-1] += c.replace(/\\(.)/,"$1");
}
return p;
}, {a: ['']}).a
输出:
[ 'foo', 'bar', 'lorem ipsum', 'baz' ]
不隶属于 StackOverflow