删除具有特定列长度的行?
Remove row with certain column length?
我有一个如下所示的文本文件:
A : 1
Boy : 3
Ahoy! : 7
more : 8
我必须删除长度小于或等于 3 个字母的行。输出应如下所示:
Ahoy! : 7
more : 8
谢谢
OP 有点不明确,并且(由于 comm(ent|un)ication)根据我对问题的解释,出现了一些可能的解决方案。
我的 1st 脚本 filter.awk
:
<= 3 { next }
{ print [=10=] }
仅考虑第 3rd 列(使用标准白色 space 分隔)。因此,冒号后的数字与常量 3
.
进行比较
你的测试输入filter.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
测试:
$ awk -f filter.awk filter.txt
Ahoy! : 7
more : 8
$
Ed Morton 指出可以做得更短:
> 3
这对我来说也是新的。 (可能是,我被 lex 弄糊涂了,它以相反的方式工作:在 lex/flex 中,所有不匹配的都被回显。)
一种更稳健的方法是使用冒号 (:
) 作为列分隔符(或者像在 awk 中命名的那样:字段分隔符)。更改字段分隔符可以通过分配内置变量 FS
来实现。这可以使用命令行参数 -F
或通过始终在开始时执行的特殊 BEGIN
规则中的赋值来完成。 (我更喜欢用字母来制作剧本"self-contained"。)
因此,filter2.awk
(即filter.awk
V2.0):
BEGIN { FS = ":" }
<= 3 { next }
{ print [=14=] }
或者考虑我今天学到的东西:
BEGIN { FS = ":" }
> 3
测试:
$ awk -f filter2.awk filter.txt
Ahoy! : 7
more : 8
$
OP 的另一种解释可能是考虑每行第一列中连续字母的数量。为此,一些内置函数开始发挥作用:
gensub()
一个强大的替换函数,不幸的是只有GNU awk可用
length()
其中returns字符串的长度(或数组中的元素个数)
为此我使用了扩展测试输入 filter2.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
Hi World : 0
filter3.awk
(即filter.awk
V3.0):
length(gensub(/(^[A-Za-z]+).*$/, "\1", 1, )) > 3
测试:
$ awk -f filter3.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
由于在这种情况下字段分隔符没有改变,所以1st字段由字符组成直到1st white space.模式 (^[A-Za-z]+)
捕获文本开头的所有字母并将它们存储到 1st 内部缓冲区中。 .*$
匹配其余部分,直到文本结束。整个文本被缓冲区 </code> 替换。 (考虑 <code>"\1"
中的转义反斜杠。)这对我在 cygwin 中的 bash 很好用,因为我曾经在我的 bash 初始化中定义了 LANG=C
(在遇到德语问题之后语言环境)。 Ed Morton(再次)指出使用 [[:alpha:]]
而不是 [A-Za-z]
应该更稳健。
如果您有非 GNU awk,则 gensub()
不可用。 (几周前,另一位大师(他的名声是 k)告诉我,世界上除了 gawks 之外没有其他 awks。检查这个,我意识到即使是我们公司的 awk Windows VS build chain 实际上也是一个 gawk。但是,自从我了解到这一点后,我多次跌跌撞撞地发现我的答案并没有被排除在外,因为我不认为解决方案是非 GNU awk 显式(或隐式)需要...)
所以这是我的第 4th 版本的非 GNU awk filter4.awk
:
{
text =
gsub(/[^[:alpha:]].*$/, "", text)
if (length(text) > 3) { print [=20=] }
}
测试:
$ awk -f filter4.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
对于 gsub()
,我恢复了正则表达式替换的逻辑:从第一个非字母字符到文本结尾的所有内容都被替换为空字符串。 (据我所知,gsub()
中甚至不存在枚举缓冲区之类的东西。)
对临时变量 text
的赋值是必要的,因为 gsub()
修改了其 3rd 参数的内容。如果我直接提供 </code> (就像我在修复它之前所做的那样),它的内容将会改变,这反过来也改变了 <code>[=50=]
.
的内容
我有一个如下所示的文本文件:
A : 1
Boy : 3
Ahoy! : 7
more : 8
我必须删除长度小于或等于 3 个字母的行。输出应如下所示:
Ahoy! : 7
more : 8
谢谢
OP 有点不明确,并且(由于 comm(ent|un)ication)根据我对问题的解释,出现了一些可能的解决方案。
我的 1st 脚本 filter.awk
:
<= 3 { next }
{ print [=10=] }
仅考虑第 3rd 列(使用标准白色 space 分隔)。因此,冒号后的数字与常量 3
.
你的测试输入filter.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
测试:
$ awk -f filter.awk filter.txt
Ahoy! : 7
more : 8
$
Ed Morton 指出可以做得更短:
> 3
这对我来说也是新的。 (可能是,我被 lex 弄糊涂了,它以相反的方式工作:在 lex/flex 中,所有不匹配的都被回显。)
一种更稳健的方法是使用冒号 (:
) 作为列分隔符(或者像在 awk 中命名的那样:字段分隔符)。更改字段分隔符可以通过分配内置变量 FS
来实现。这可以使用命令行参数 -F
或通过始终在开始时执行的特殊 BEGIN
规则中的赋值来完成。 (我更喜欢用字母来制作剧本"self-contained"。)
因此,filter2.awk
(即filter.awk
V2.0):
BEGIN { FS = ":" }
<= 3 { next }
{ print [=14=] }
或者考虑我今天学到的东西:
BEGIN { FS = ":" }
> 3
测试:
$ awk -f filter2.awk filter.txt
Ahoy! : 7
more : 8
$
OP 的另一种解释可能是考虑每行第一列中连续字母的数量。为此,一些内置函数开始发挥作用:
gensub()
一个强大的替换函数,不幸的是只有GNU awk可用length()
其中returns字符串的长度(或数组中的元素个数)
为此我使用了扩展测试输入 filter2.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
Hi World : 0
filter3.awk
(即filter.awk
V3.0):
length(gensub(/(^[A-Za-z]+).*$/, "\1", 1, )) > 3
测试:
$ awk -f filter3.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
由于在这种情况下字段分隔符没有改变,所以1st字段由字符组成直到1st white space.模式 (^[A-Za-z]+)
捕获文本开头的所有字母并将它们存储到 1st 内部缓冲区中。 .*$
匹配其余部分,直到文本结束。整个文本被缓冲区 </code> 替换。 (考虑 <code>"\1"
中的转义反斜杠。)这对我在 cygwin 中的 bash 很好用,因为我曾经在我的 bash 初始化中定义了 LANG=C
(在遇到德语问题之后语言环境)。 Ed Morton(再次)指出使用 [[:alpha:]]
而不是 [A-Za-z]
应该更稳健。
如果您有非 GNU awk,则 gensub()
不可用。 (几周前,另一位大师(他的名声是 k)告诉我,世界上除了 gawks 之外没有其他 awks。检查这个,我意识到即使是我们公司的 awk Windows VS build chain 实际上也是一个 gawk。但是,自从我了解到这一点后,我多次跌跌撞撞地发现我的答案并没有被排除在外,因为我不认为解决方案是非 GNU awk 显式(或隐式)需要...)
所以这是我的第 4th 版本的非 GNU awk filter4.awk
:
{
text =
gsub(/[^[:alpha:]].*$/, "", text)
if (length(text) > 3) { print [=20=] }
}
测试:
$ awk -f filter4.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
对于 gsub()
,我恢复了正则表达式替换的逻辑:从第一个非字母字符到文本结尾的所有内容都被替换为空字符串。 (据我所知,gsub()
中甚至不存在枚举缓冲区之类的东西。)
对临时变量 text
的赋值是必要的,因为 gsub()
修改了其 3rd 参数的内容。如果我直接提供 </code> (就像我在修复它之前所做的那样),它的内容将会改变,这反过来也改变了 <code>[=50=]
.