我有以下运行良好的 pcre:
/[c,f]=("(?:[a-z A-Z 0-9]|-|_|\/)+\.(?:js|html)")/g
它根据输入生成所需的输出“foo.js”和“bar.html”
<script src="foo.js"...
<link rel="import" href="bar.html"...
问题是,OS X 版本的 grep 似乎没有像 -o
这样的选项来只打印捕获的组(根据另一个 SO 问题,这显然适用于 linux)。由于这将是 makefile 的一部分,我需要一个可以在任何 *nix 平台上运行的版本。
我尝试了 sed 但以下内容
s/[c,f]=("(?:[[:alphanum:]]|-|_|\/)+\.(?:js|html)")/\1/pg
抛出错误:“重复运算符的操作数无效”。我试过将其删除,不包括文件路径分隔符,我似乎无法破解它。将我的 pcre 转换成我几乎可以保证在符合 POSIX 标准(即使是非官方的)平台上的东西有什么帮助吗?
附言我知道我编写的正则表达式中固有的潜在故障模式,它只会用于具有相当特定格式的非常特定的文件。
最佳答案
POSIX 定义了两种风格的正则表达式:
BREs (Basic Regular Expressions) - 功能较少且需要
\
的旧版本-转义某些元字符,特别是\(
,\)
和\{
,\}
, 并且不支持重复符号\+
(用\{1,\}
模拟)和\?
(用\{0,1\}
模拟),不支持\|
(交替;无法被模拟)。EREs (Extended Regular Expressions) - 更现代的风格,但是缺少正则表达式内部的反向引用(这与捕获组不相同); 不支持词边界断言(例如
\<
),不支持捕获组.
POSIX 还规定哪些实用程序支持哪种风格:哪些支持 BRE,哪些支持 ERE,哪些可选支持任一个,哪些 em>专门仅支持 BRE,或仅支持 ERE;特别是:
-
grep
默认使用 BRE,但可以使用-E
启用 ERE -
sed
,遗憾的是,只有支持 BRE- GNU 和 BSD
sed
,但是,- 作为一个非标准扩展 - 确实 支持带有-E
的 ERE开关(GNUsed
的更广为人知的别名是-r
,但也支持-E
)。
- GNU 和 BSD
-
awk
仅支持ERE
此外,Linux 和 BSD/OSX 上的正则表达式库实现了对 POSIX ERE 语法的扩展 - 遗憾的是,这些扩展部分不兼容(例如单词边界断言的语法)。
至于您的特定正则表达式:
它使用非捕获组的语法,(?:...)
;但是,捕获组在 grep
的上下文中毫无意义,因为 grep
不提供替换功能。
如果我们删除这个方面,我们得到:
[c,f]=("([a-z A-Z 0-9]|-|_|\/)+\.(js|html)")
现在这是一个有效的 POSIX ERE(可以简化 - 参见 Benjamin W's helpful answer)。
然而,由于它是一个扩展 RE,使用sed
不是一个选项,如果你想保持严格的 POSIX 兼容。
因为 GNU 和 BSD/OSX sed
恰好实现-E
为了支持 ERE,您可以逃脱 sed
,如果这些平台是您唯一需要支持的平台 - 请参阅 anubhava's answer .
同样,GNU 和 BSD/OSX grep
碰巧实现了非标准 -o
选项(与您在问题中陈述的不同),因此,如果这些平台是您唯一需要支持的平台,您可以使用:
$ grep -Eo '[c,f]=("([a-z A-Z 0-9]|-|_|\/)+\.(js|html)")' file | cut -c 3-
c="foo.js"
f="bar.html"
(请注意,只有 GNU grep
支持 -P
以启用 PCRE,这只是解决方案(请注意 \K
,它会丢弃目前匹配的所有内容):
$ grep -Po '[c,f]=\K("([a-z A-Z 0-9]|-|_|\/)+\.(js|html)")' file
)
如果您真的想要严格符合 POSIX 标准的解决方案,您可以使用awk
:
$ awk -F\" '/[c,f]=("([a-z A-Z 0-9]|-|_|\/)+\.(js|html)")/ { print "\"" $2 "\"" }' file
关于regex - 将 PCRE 模式转换为 POSIX,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35686860/