我想将类似命令行的字符串拆分为单个字符串参数。它所需的正则表达式如何书写?问题在于参数可能会被引号引起来。例如:
"param 1" param2 "param 3"
应该拆分为: param 1, param2, param 3
"param 1" param2 "param 3"
应该拆分为: param 1, param2, param 3
你不应该使用正则表达式来处理这个问题。相反,编写一个解析器或使用语言提供的解析器。
我不明白为什么会因此被踩。在Python中可以这样实现:
>>> import shlex
>>> shlex.split('"param 1" param2 "param 3"')
['param 1', 'param2', 'param 3']
>>> shlex.split('"param 1" param2 "param 3')
Traceback (most recent call last):
[...]
ValueError: No closing quotation
>>> shlex.split('"param 1" param2 "param 3\\""')
['param 1', 'param2', 'param 3"']
现在告诉我,为了解决这个问题而费尽心思地构建正则表达式是否值得麻烦。
("[^"]+"|[^\s"]+)
我使用C++
#include <iostream>
#include <iterator>
#include <string>
#include <regex>
void foo()
{
std::string strArg = " \"par 1\" par2 par3 \"par 4\"";
std::regex word_regex( "(\"[^\"]+\"|[^\\s\"]+)" );
auto words_begin =
std::sregex_iterator(strArg.begin(), strArg.end(), word_regex);
auto words_end = std::sregex_iterator();
for (std::sregex_iterator i = words_begin; i != words_end; ++i)
{
std::smatch match = *i;
std::string match_str = match.str();
std::cout << match_str << '\n';
}
}
输出:
"par 1"
par2
par3
"par 4"
不考虑实现语言,您的正则表达式可能如下所示:
("[^"]*"|[^"]+)(\s+|$)
第一部分"[^"]*"
查找不包含嵌入引号的引用字符串,第二部分[^"]+
查找非引号字符序列。 \s+
匹配一个分隔空格序列,$
匹配字符串的结尾。
正则表达式:/[\/-]?((\w+)(?:[=:]("[^"]+"|[^\s"]+))?)(?:\s+|$)/g
示例:/P1="长字符串" /P2=3 /P3=short PwithoutSwitch1=any PwithoutSwitch2
这个正则表达式可以解析按以下规则构建的参数列表:
/
或 -
)。=
) 或冒号 (:
) 分隔。这个正则表达式有三个组:
对于上面的示例:
/P1="长字符串"
P1="长字符串"
,P1
,"长字符串"
。/P2=3
P2=3
,P2
,3
。/P3=short
P3=short
,P3
,short
。PwithoutSwitch1=any
PwithoutSwitch1=any
,PwithoutSwitch1
,any
。PwithoutSwitch2
PwithoutSwitch2
,PwithoutSwitch2
,这将从参数中分离出一个exe;从exe中去除括号;假设数据干净:
^(?:"([^"]+(?="))|([^\s]+))["]{0,1} +(.+)$
每次你将会有两个匹配,分别是三个匹配组:
示例:
"C:\WINDOWS\system32\cmd.exe" /c echo this
匹配 1:C:\WINDOWS\system32\cmd.exe
匹配 2:$null
匹配 3:/c echo this
C:\WINDOWS\system32\cmd.exe /c echo this
匹配 1:$null
匹配 2:C:\WINDOWS\system32\cmd.exe
匹配 3:/c echo this
"C:\Program Files\foo\bar.exe" /run
匹配1:C:\Program Files\foo\bar.exe
匹配2:$null
匹配3:/run
想法:
我��信你需要创建一个循环来捕获可能无限数量的参数。
这个正则表达式可以轻松地循环到第三个匹配,直到匹配失败;没有更多的参数了。
既然有 Python 的答案,那我们也应该有 Ruby 的答案 :)
require 'shellwords'
Shellwords.shellsplit '"param 1" param2 "param 3"'
#=> ["param 1", "param2", "param 3"] or :
'"param 1" param2 "param 3"'.shellsplit
虽然答案不是正则表达式特定的,但回答了Python命令行参数解析:
import sys
def parse_cmd_args():
_sys_args = sys.argv
_parts = {}
_key = "script"
_parts[_key] = [_sys_args.pop(0)]
for _part in _sys_args:
# Parse numeric values float and integers
if _part.replace("-", "1", 1).replace(".", "1").replace(",", "").isdigit():
_part = int(_part) if '.' not in _part and float(_part)/int(_part) == 1 else float(_part)
_parts[_key].append(_part)
elif "=" in _part:
_part = _part.split("=")
_parts[_part[0].strip("-")] = _part[1].strip().split(",")
elif _part.startswith(("-")):
_key = _part.strip("-")
_parts[_key] = []
else:
_parts[_key].extend(_part.split(","))
return _parts