正则表达式具有未知数量参数的字符串
Posted
技术标签:
【中文标题】正则表达式具有未知数量参数的字符串【英文标题】:Regex a string with unknown number of parameters 【发布时间】:2016-08-16 08:44:54 【问题描述】:假设我在这种格式的文本文件中有数百万个字符串:
st=expand&c=22&t=button&k=fun HTTP
这是一个字符串,我们可以将其视为带有键 st
、c
、t
和 k
的散列。文本文件中的某些字符串可能不存在给定的 &KEY=VALUE,因此可能如下所示:
st=expand&k=fun HTTP
如何使用 sed 将字符串更改为跟随
expand,,,fun
也就是说,即使 key=value 不存在,我们仍然添加逗号。我们可以假设我们有一个固定的密钥集[st,c,t,k]
。
我尝试过的类似于(只是一个想法!!)
sed 's/\(st=\|c=\|t=\|k=\)\([\(^\&\|HTTP\)])\(\&\|HTTP\)/\3,/g' big_file
但显然,如果c
不存在,则它不会添加逗号,因为它找不到任何逗号。任何想法如何解决这个问题?也可以使用awk
(或任何其他快速文本处理实用程序)
谢谢!
输入数据示例
st=expand&c=22&t=button&k=fun HTTP
c=22&t=button&k=fun HTTP
st=expand&c=22&t=party&k=fun HTTP
st=expand&c=22&k=fun HTTP
st=expand HTTP
HTTP
输出数据
expand,22,button,fun
,22,button,fun
expand,22,party,fun
expand,22,,fun
expand,,,
,,,
【问题讨论】:
不,这里的 3 无关紧要,请不要太在意这个例子 >) 把它放在那里表明我是怎么想的(通过匹配一些东西并把,
当没有什么可以匹配时)
我认为用您的预期输出显示更多输入数据会更好
为什么选择 sed?这完全是错误的工作工具。使用真正的编程语言,将&
上的字符串和=
上的部分拆分成哈希表并输出。
我有一个大约 20 亿行的“文件”,确实需要性能。而且由于我已经在使用 sed 来更改该文件中的其他内容,因此我希望可以将它与其他 sed 命令一起使用。也许那是不可能的,但我想这就是我在这里的原因。
这将是什么,20GB+?你不会受到 IO 限制,而不是处理器限制吗?
【参考方案1】:
你可以使用这个sed
:
sed -E 's/(st=([^& ]*)|)(.*c=([^& ]*)|)(.*t=([^& ]*)|)(.*k=([^& ]*)|) HTTP/\2,\4,\6,\8/' file
expand,22,button,fun
,22,button,fun
expand,22,party,fun
expand,22,,fun
expand,,,
,,,
Sed Demo
RegEx Demo
【讨论】:
【参考方案2】:只要您的输入数据中有 name=value 对,创建 name->value 数组然后按您想要的任何顺序按名称打印值是最简单、最清晰且通常最有效的方法,例如:
$ cat tst.awk
BEGIN FS="[&= ]"; OFS=","
delete n
for (i=1;i<NF;i+=2)
n[$i] = $(i+1)
print n["st"], n["c"], n["t"], n["k"]
$ awk -f tst.awk file
expand,22,button,fun
,22,button,fun
expand,22,party,fun
expand,22,,fun
expand,,,
,,,
【讨论】:
【参考方案3】:sed
尝试的另一种模式:
sed -r "s/(st=(\w+))?(&?c=(\w+))?(&t=(\w+))?(&k=(\w+))?( HTTP)/\2,\4,\6,\8/g" big_file
expand,22,button,fun
,22,button,fun
expand,22,party,fun
expand,22,,fun
expand,,,
REGEX 101 DEMO
【讨论】:
【参考方案4】:这样的事情怎么样?这不是非常严格,但只要您的数据遵循您在每一行中描述的格式,它就可以工作。
正则表达式:
^(?:st=([^&\n]*))?&?(?:c=([^&\n]*))?&?(?:t=([^&\n]*))?&?(?:k=([^&\n]*))? HTTP$
(必须每行运行一次或启用多行和全局选项)
替换:
\1,\2,\3,\4
在这里试试:https://regex101.com/r/nE1oP7/2
编辑:如果您使用 sed,则需要将非捕获组更改为常规组((?:)
到 ()
)并相应地更新反向引用(\2,\4,\6,\8
)。演示:http://ideone.com/GNRNGp
【讨论】:
如果您要发布一个正则表达式,请展示它在特定工具的上下文中工作。在某些在线“正则表达式验证器”工具中显示它是没有用的,除非您建议 OP 将他的输入文件上传到该网站以在它们上运行正则表达式。您发布的正则表达式不适用于任何标准 UNIX 工具。 怎么没用? Playground 工具的目的是让您对少量数据进行实验,以便您了解正在发生的事情。我提供了一个逻辑建议。它可能需要一些调整,但答案不一定要在特定工具的上下文中才有价值。 它没用,因为它在 OP 使用的任何工具中都不起作用,并且不需要调整即可工作,它需要完全重写。您也可以告诉 OP 如何在汇编代码中执行此操作,以便为他带来所有实际的好处。为了准确起见,您必须将 EDIT 更改为This will not work in sed, awk or any other standard UNIX tool. You will have to completely rewrite the syntax depending on the tool you end up using.
。如果它可以在 perl 或 ruby 或其他东西(我怀疑但 idk)中工作,那么至少给读者一个线索,知道哪个(如果有的话)可以工作。
你对这个有点粗鲁。请记住,答案不仅对提出问题的人有帮助,而且对后来遇到类似情况的其他人也有帮助,他们可能有不同的环境,但有相同的业务问题。再次,我提供了一个建议。它绝对适用于一些正则表达式解析器。我写的时候不知道它在 sed 中不起作用,但它仍然有助于 OP 思考如何构建这样的模式。
我继续并让它与 sed 一起工作,并进行了非常小的调整,将非捕获组更改为常规组并更新反向引用。正如我所说,它只需要进行一些调整以适应该工具,而不是像您所说的那样完全重写。演示:ideone.com/GNRNGp 没有必要像你那样撕毁我的答案,而且你绝对不正确,因为我的答案没有用,正如我在这里展示的那样。不管你是不是有意的,你的 cmets 都带着一种有损这里协作环境的自我意识。以上是关于正则表达式具有未知数量参数的字符串的主要内容,如果未能解决你的问题,请参考以下文章