删除具有特定列长度的行?

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 的另一种解释可能是考虑每行第一列中连续字母的数量。为此,一些内置函数开始发挥作用:

  1. gensub()一个强大的替换函数,不幸的是只有GNU awk可用

  2. 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=].

的内容