将不同的正则表达式可能性合并为一个
join different regex possibilities into one
是否可以将以下正则表达式合二为一?
cat file.txt | \
sed 's/\tNULL\t/\t\N\t/g' | \
sed 's/^NULL\t/\N\t/g' | \
sed 's/\tNULL$/\t\N/g' | \
sed 's/^NULL$/\N/g''
也许还有一件事要补充,这每月要处理数十亿行,因此性能是一个考虑因素。
解决方案基准测试
谢谢大家的建议,perl
运行 对我来说是最快的。如果您想知道:
[/tmp]$ time cat /tmp/result_w_null.txt > /dev/null
real 0m0.045s
user 0m0.000s
sys 0m0.042s
[/tmp]$ time cat /tmp/result_w_null.txt | sed 's/\<NULL\>/\N/g' > /dev/null
real 0m5.843s
user 0m2.472s
sys 0m3.852s
[/tmp]$ time cat /tmp/result_w_null.txt | sed 's/\tNULL\t/\t\N\t/g' | sed 's/^NULL\t/\N\t/g' | sed 's/\tNULL$/\t\N/g' | sed 's/^NULL$/\N/g' > /dev/null
real 0m7.078s
user 0m7.148s
sys 0m4.963s
#Suggestions:
[/tmp]$ time cat /tmp/result_w_null.txt | awk -F'\t' -v OFS='\t' '{for (i=1;i<=NF;i++) if ($i=="NULL") $i="\N"}1' > /dev/null
real 0m20.196s
user 0m14.876s
sys 0m7.145s
[/tmp]$ time cat /tmp/result_w_null.txt | awk -v RS='(^|[\t\n])NULL(\tNULL)*([\t\n]|$)' '{ gsub(/NULL/, "\N", RT); ORS=RT} 1' > /dev/null
real 0m10.611s
user 0m8.743s
sys 0m3.754s
[/tmp]$ time cat /tmp/result_w_null.txt | sed -E ':a; s/(\t|^)NULL(\t|$)/\N/g; ta' > /dev/null
real 0m9.673s
user 0m5.723s
sys 0m5.678s
[/tmp]$ time cat /tmp/result_w_null.txt | perl -pe 's/(?:\t|^)\KNULL(?=\t|$)/\N/g' > /dev/null
real 0m4.452s
user 0m3.237s
sys 0m2.288s
您可以使用
sed -E 's/(\t|^)NULL(\t|$)/\N/g;'
如果可以连续匹配
sed -E ':a; s/(\t|^)NULL(\t|$)/\N/g; ta'
看到一个online demo。
POSIX ERE 正则表达式匹配
(\t|^)
- 捕获第 1 组(替换模式中的 </code>):制表符或字符串开头 </li>
<li><code>NULL
- 文字字符串
(\t|$)
- 捕获第 2 组(替换模式中的 </code>):制表符或字符串结尾。</li>
</ul>
<p>对于连续匹配,您需要循环匹配,方法是设置一个标签(<code>:a
),然后使用ta
分支到它。这是一种解决缺少前瞻性支持的方法,该支持允许在不 消耗 的情况下检查尾随选项卡。在 Perl 中,您将使用
perl -pe 's/(?:\t|^)\KNULL(?=\t|$)/\N/g'
哪里
(?:\t|^)
- 匹配制表符或字符串开头的非捕获组
\K
- 丢弃到目前为止匹配的所有文本的匹配重置运算符
NULL
- 文字字符串
(?=\t|$)
- 正前瞻要求紧靠当前位置右侧的制表符或字符串结尾。
awk
这种用法可能更容易理解:
awk '
BEGIN {FS = OFS = "\t"}
{
for (i=1; i<=NF; i++)
if ($i == "NULL")
$i = "\N"
print
}
' file.txt
或者,单行化
awk -F'\t' -v OFS='\t' '{for (i=1;i<=NF;i++) if ($i=="NULL") $i="\N"}1' file.txt
这是一个替代的 gnu-awk 解决方案:
cat file
abc NULL foo
NULL bar
xyz NULL
pqr mnop
NULL
将 gnu-awk
与自定义 RS
结合使用:
awk -v RS='(^|[\t\n])NULL(\tNULL)*([\t\n]|$)' '{
gsub(/NULL/, "\N", RT); ORS=RT} 1' file
abc \N foo
\N bar
xyz \N
pqr mnop
\N
是否可以将以下正则表达式合二为一?
cat file.txt | \
sed 's/\tNULL\t/\t\N\t/g' | \
sed 's/^NULL\t/\N\t/g' | \
sed 's/\tNULL$/\t\N/g' | \
sed 's/^NULL$/\N/g''
也许还有一件事要补充,这每月要处理数十亿行,因此性能是一个考虑因素。
解决方案基准测试
谢谢大家的建议,perl
运行 对我来说是最快的。如果您想知道:
[/tmp]$ time cat /tmp/result_w_null.txt > /dev/null
real 0m0.045s
user 0m0.000s
sys 0m0.042s
[/tmp]$ time cat /tmp/result_w_null.txt | sed 's/\<NULL\>/\N/g' > /dev/null
real 0m5.843s
user 0m2.472s
sys 0m3.852s
[/tmp]$ time cat /tmp/result_w_null.txt | sed 's/\tNULL\t/\t\N\t/g' | sed 's/^NULL\t/\N\t/g' | sed 's/\tNULL$/\t\N/g' | sed 's/^NULL$/\N/g' > /dev/null
real 0m7.078s
user 0m7.148s
sys 0m4.963s
#Suggestions:
[/tmp]$ time cat /tmp/result_w_null.txt | awk -F'\t' -v OFS='\t' '{for (i=1;i<=NF;i++) if ($i=="NULL") $i="\N"}1' > /dev/null
real 0m20.196s
user 0m14.876s
sys 0m7.145s
[/tmp]$ time cat /tmp/result_w_null.txt | awk -v RS='(^|[\t\n])NULL(\tNULL)*([\t\n]|$)' '{ gsub(/NULL/, "\N", RT); ORS=RT} 1' > /dev/null
real 0m10.611s
user 0m8.743s
sys 0m3.754s
[/tmp]$ time cat /tmp/result_w_null.txt | sed -E ':a; s/(\t|^)NULL(\t|$)/\N/g; ta' > /dev/null
real 0m9.673s
user 0m5.723s
sys 0m5.678s
[/tmp]$ time cat /tmp/result_w_null.txt | perl -pe 's/(?:\t|^)\KNULL(?=\t|$)/\N/g' > /dev/null
real 0m4.452s
user 0m3.237s
sys 0m2.288s
您可以使用
sed -E 's/(\t|^)NULL(\t|$)/\N/g;'
如果可以连续匹配
sed -E ':a; s/(\t|^)NULL(\t|$)/\N/g; ta'
看到一个online demo。
POSIX ERE 正则表达式匹配
(\t|^)
- 捕获第 1 组(替换模式中的</code>):制表符或字符串开头 </li> <li><code>NULL
- 文字字符串(\t|$)
- 捕获第 2 组(替换模式中的</code>):制表符或字符串结尾。</li> </ul> <p>对于连续匹配,您需要循环匹配,方法是设置一个标签(<code>:a
),然后使用ta
分支到它。这是一种解决缺少前瞻性支持的方法,该支持允许在不 消耗 的情况下检查尾随选项卡。在 Perl 中,您将使用perl -pe 's/(?:\t|^)\KNULL(?=\t|$)/\N/g'
哪里
(?:\t|^)
- 匹配制表符或字符串开头的非捕获组\K
- 丢弃到目前为止匹配的所有文本的匹配重置运算符NULL
- 文字字符串(?=\t|$)
- 正前瞻要求紧靠当前位置右侧的制表符或字符串结尾。
awk
这种用法可能更容易理解:
awk '
BEGIN {FS = OFS = "\t"}
{
for (i=1; i<=NF; i++)
if ($i == "NULL")
$i = "\N"
print
}
' file.txt
或者,单行化
awk -F'\t' -v OFS='\t' '{for (i=1;i<=NF;i++) if ($i=="NULL") $i="\N"}1' file.txt
这是一个替代的 gnu-awk 解决方案:
cat file
abc NULL foo
NULL bar
xyz NULL
pqr mnop
NULL
将 gnu-awk
与自定义 RS
结合使用:
awk -v RS='(^|[\t\n])NULL(\tNULL)*([\t\n]|$)' '{
gsub(/NULL/, "\N", RT); ORS=RT} 1' file
abc \N foo
\N bar
xyz \N
pqr mnop
\N