我想知道是否有人可以为我提供解析字符串所需的正则表达式,例如:
'foo bar "多字标签"'
进入标签数组,如:
["foo","bar","多字标签"]
谢谢
在红宝石中
scan(/\"([\w ]+)\"|(\w+)/).flatten.compact
例如
"foo bar \"multiple words\" party_like_1999".scan(/\"([\w ]+)\"|(\w+)/).flatten.compact
=> ["foo", "bar", "multiple words", "party_like_1999"]
您可以实施扫描仪来执行此操作。例如,在 Python 中,它看起来像这样:
import re
scanner = re.Scanner([
(r"[a-zA-Z_]\w*", lambda s,t:t), # regular tag
(r"\".*?\"", lambda s,t:t[1:-1]), # multi-word-tag
(r"\s+", None), # whitespace not in multi-word-tag
])
tags, _ = scanner.scan('foo bar "multiple word tag"')
print tags
# ['foo', 'bar', 'multiple word tag']
这称为词法分析。
首先,我建议使用split()
方法/函数而不是正则表达式来执行此操作。大多数语言都有这样的东西,您可以调用它来将字符串拆分为单词(由空格分隔),并且您通常可以指定要将其拆分为多少部分的上限。所以一般来说,
split('foo bar "multiple word tag"', ' ', 3)
其中 3 表示不超过 3 个部分,适用于您的示例。您可以使用trim()
orstrip()
方法/函数(或编写一个)来删除任何前导和尾随引号。
如果你打算用正则表达式来做,也许是因为每一行可能有可变数量的标签,在某种程度上它取决于你到底用什么来做解析,因为不同的正则表达式引擎有时有不同的方式代表相同的事物。而且我认为它不能仅用一个普通的旧正则表达式来完成。你需要一些代码来配合它。例如,这是一个使用 Perl 兼容的正则表达式(或类似的东西,无论如何)的(伪?)伪代码解决方案:
pos = 0;
while pos < length(string):
# match(regular expression, string to search, starting position for the search)
m = match(/\s*(".+?"|\S+)?\s*/, string, pos);
tag = m.group(1).strip('"');
# process the tag
对于它的价值,我可能会使用 DFA(离散有限自动机)来执行此操作,它逐个字符地遍历字符串,将每个字符附加到缓冲区并在到达标记末尾时刷新缓冲区(或者是因为空格或右引号)。也许只有我一个人,但我觉得这是一个非常简单的解析任务,就 DFA 状态而言(在我看来)会更容易理解。
适用于任何 match->array 函数的通用正则表达式:
(?<=")[^"]+|\w+
(如果不只允许使用字母数字和引号,使用\S+
而不是\w+
可能有意义。)
红宝石示例:
myarray = mystring.scan(/(?<=\")[^\"]+|\w+/)
(未经测试)
我们开始(Perl 风格):
^(?:"([^"]*?)"|(\S+?)|\s*?)*$
解释:
^ // from begginning
(?: // non-capturing group of three alternatives
"([^"]*?)" // capture "tag" "
|
(\S+?) // capture tag
|
\s*? // ignore whitespace
)*
$ // until the end of the line
正则表达式几乎肯定不会是您在这里寻找的解决方案。正则表达式可用于从较大的字符串中解析一组匹配的输入。例如,如果我只想从电子邮件地址中获取用户名,我可以使用以下正则表达式来获取数据
"^(?<username>[\w\d]+)@.*$"
该名称将出现在名称组“用户名”中
在您的情况下,您并没有尝试获取输入字符串的子集。您正在尝试匹配整个字符串的元素。在一天结束时,正则表达式只会说“是的,它匹配”或“不,它不匹配”。为了获取内容,您需要实际解析出字符串。