我想为与正则表达式匹配的值运行自定义替换实用程序。这意味着对于正则表达式的每个匹配项,调用包含匹配项的字符的自定义实用程序。自定义实用程序的输出将替换原始字符。
可以使用factor
来说明,但这种情况不应该被认为是详尽的,例如可能希望包含带有$
、%
和算术运算符的表达式:
$ factor 230
230: 2 5 23
使用此实用程序并为输入中的所有整数调用它,这是一个示例输入和输出:
$ [code] <<< 'Given these numbers: 27, 13, 230, and 19, it is evident which are primes.'
Given these numbers: 27: 3 3 3, 13: 13, 230: 2 5 23, and 19: 19, it is evident which are primes.
我认为这可能会起作用,但看起来它试图直接解释输入。使用sed (GNU sed) 4.2.2
.
$ sed -E 's/([0-9]+)/factor 1/ge' <<< 'Given these numbers: 27, 13, 230, and 19, it is evident which are primes.'
sh: 1: Given: not found
显然我不明白e
标志的作用。我尝试在awk
这样做:
$ awk '{r = gensub(/([0-9]+)/, system("factor \1"), "g"); print r}' <<< 'Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes.'
1:
Given the numbers with factors: 0, 0, 0, and 0, it is evident which are primes.
我不确定1:
来自哪里,但很明显它只打印了system
的返回代码。似乎没有办法从awk
中的命令捕获标准输出。
我在核心实用程序中要求的东西是可能的吗?
将数字替换为每个数字上的factor
输出
echo "Given these numbers: 27, 13, 230, and 19, it is evident which are primes." |
perl -wnE'say s{([0-9]+)}{$f=qx(factor $1); chomp $f; $f}egr'
这使用/e
修饰符将替换端作为代码进行评估。qx
运行命令并返回其输出,换行符由chomp
删除。有了/g
,它会不断通过字符串来替换所有数字。有关说明,请参见下文。
使用/r
修饰符,替换运算符s///
返回修改后的字符串。
输出:
给定这些数字:27:3 3 3,13:13,230:2 5 23和19:19,很明显哪些是素数。
请继续阅读其他方法的解释。
原始帖子
例如,从输入行中提取数字并在其上调用每个程序
echo "Given these numbers: 27, 13, 230, and 19, it is evident which are primes."
| perl -wnE'say "Result: ", join(",", map { qx(factor $_) } /([0-9]+)/g)'
列表上下文中的正则表达式匹配运算符†返回匹配项,而/g
修饰符使其查找所有匹配项。该列表将传递给 map,映射将其主体中的代码应用于每个元素并返回结果列表。qx
是反引号的运算符形式,它返回命令的输出,似乎是您想要的。
我将输出的格式留给您,这里的列表由,
连接,并以字符串作为前缀。
如果输入行在文件中
perl -wnE'say "Result: ", join(",", map { qx(factor $_) } /([0-9]+)/g)' file
对于更复杂的处理,您可以将匹配列表分配给数组 然后随心所欲地做
perl -wnE'@n = /([0-9]+)/g; for (@n) { say "process $_" }' file
这将一次处理一行输入。
更简单地说,在每个号码匹配时调用程序factor
perl -wnE'while (/([0-9]+)/g) { say qx(factor $1) }' file
while
条件中的正则表达式在每次迭代中不断寻找匹配项,从前一个匹配的位置继续,凭借标量上下文中的/g
修饰符†。在身体内部,您可以对每场捕获的比赛做您需要的事情,这是$1
。
† 首次使用/g
时的列表上下文 是强加的,因为map
将列表作为输入。在第二个上下文中,上下文是标量,因为while
条件中的代码被计算为标量。
awk 命令输出中的1
来自您打印来自system()
的返回代码。system()
返回它调用的命令的退出状态,而不是命令的输出 - 它只是转到 stdout。此外,对于您使用的语法,system() 是在 gensub() 之前调用的,因此您使用文字字符串\1
调用因子。
正确的语法来做你试图用 GNU awk 做的事情:
awk '{r = gensub(/([0-9]+)/, system("factor \1"), "g"); print r}'
这是可以与任何awk一起使用的吗:
$ awk '{
head = ""
while ( match($0,/[0-9]+/) ) {
cmd = "factor " substr($0,RSTART,RLENGTH)
ret = ( (cmd | getline line) > 0 ? line : cmd " failed" )
close(cmd)
head = head substr($0,1,RSTART-1) ret
$0 = substr($0,RSTART+RLENGTH)
}
$0 = head $0
print
}' <<< 'Given these numbers: 27, 13, 230, and 19, it is evident which are primes.'
Given these numbers: 27: 3 3 3, 13: 13, 230: 2 5 23, and 19: 19, it is evident which are primes.
使用 GNU awk 将第 4 个 arg 转换为 split(),它可以写成:
$ awk '{
n = split($0,others,/[0-9]+/,nums)
$0 = ""
for (i=1; i<n; i++) {
cmd = "factor " nums[i]
ret = ( (cmd | getline line) > 0 ? line : cmd " failed" )
close(cmd)
$0 = $0 others[i] ret
}
$0 = $0 others[n]
print
}' <<< 'Given these numbers: 27, 13, 230, and 19, it is evident which are primes.'
Given these numbers: 27: 3 3 3, 13: 13, 230: 2 5 23, and 19: 19, it is evident which are primes.
以下是替换字符串中文本的解决方案:
perl -MList::Util=pairs -E '($m,$s) = ($_->key,$_->value) and $ARGV[0] =~ s/$m/$s/ for pairs map {$_, qx/factor $_/} $ARGV[0] =~ /(d+)/g; say $ARGV[0]'
'Given these numbers: 27, 13, 230, and 19, it is evident which are primes'
请注意,factor
的输出末尾有一个换行符。
这可能对你有用(GNU sed):
sed 's/[0-9]+/$(factor &)/g;s/.*/echo "&"/e' file
用内联函数调用将所有数字括起来,然后用双引号括住整个字符串,并使用echo
计算该字符串。