使用 awk 对列表进行分类

使用 awk 对列表进行分类
#!/bin/bash

PASTE=$(xclip -o)

curl -s https://website.com/$PASTE | dos2unix | grep -A3 '<td class="hidden-xs"' | sed 's/<[^>]*//1g; s/>//g; s/  //g; s/\\r//g; /^$/d; s/--/-/g; s/&#246;/ö/g; s/&#252;/ü/g; s/&#231;/ç/g' | awk '!/^Genel/ || !f++'

它生成以下结果:

General
hit
definition 1
-
General
hit
definition 2
-
... 
-
Idiom
hit the sack
Definition 
-
Idiom
hit the buffers
Definition 1
-
Idiom
hit the buffers
Definition 2

我试图对其进行分类,并使结果如下:

General
hit
definition 1
definition 2
definition ...
-
Idiom
hit the sack
Definition 
-
hit the buffers
Definition 1
Definition 2

答案1

使用awk

awk '
$0=="General" || $0=="Idiom"{
  type=$0;  getline
  group=$0; getline

  key=type","group  
  if (key in b){
    b[key]=b[key]"\n"$0
  }
  else {
    if (type=="General" && !isfirstgeneral){
      type=type"\n"; isfirstgeneral=1
    }
    else if (type=="Idiom" && !isfirstidiom){
      type=type"\n"; isfirstidiom=1
    }
    else {
      type=""
    }
    a[++cnt]=key
    b[key]=type group"\n"$0
  }
}
END{
  for (i=1;i<=cnt;i++){
    print b[a[i]]
    if (i<cnt) print "-"
  }
}' file

如果一行是GeneralIdiom,则将此行另存为type并获取接下来的两行(称为group,“定义”为$0)。

使用两个数组作为技巧来防止awk循环时数组元素可能出现混乱排序:

  • 具有整数键的数组存储由以下行组成的a数组的键btypegroup
  • 数组b保存给定键收集的字符串

当数组的组合键b不存在时,创建两个新的数组元素。字符串type仅在第一次遇到时保存(如果这是输出中的错误,则删除 -blockif-else if-else并替换b[key]=type group"\n"$0b[key]=type"\n"group"\n"$0)。

如果该键存在,则将“definition”字符串附加到现有的数组值中。

在该部分中,使用数组顺序END打印数组值,后跟分隔线。ba

(我将您的输入保存为 file file,但如果您愿意,您可以将命令的输出通过管道传输curl到此 awk 脚本中。)

输出:

General
hit
definition 1
definition 2
-
Idiom
hit the sack
Definition
-
hit the buffers
Definition 1
Definition 2

更新

要使用类别列表,请将类别添加到文本文件中,每个类别一行。

例子categories.txt

General
Idiom
Computer
What ever

将脚本更改为

awk '
NR==FNR{
  cat[$0]; next
}
$0 in cat{
  type=$0;  getline
  group=$0; getline

  key=type","group  
  if (key in b){
    b[key]=b[key]"\n"$0
  }
  else {
    a[++cnt]=key
    b[key]=group"\n"$0
  }
}
END{
  for (i=1;i<=cnt;i++){
    # print first occurrence of category
    catname=a[i]
    sub(/,.*/, "", catname)
    if (catname in cat){
      print catname
      delete cat[catname]
    }

    print b[a[i]]
    if (i<cnt) print "-"
  }
}' categories.txt file

答案2

awk关联数组的使用有点厚颜无耻......

awk '$0=="General"||$0=="Idiom"{
    cat=$0;getline; def=$0; getline;
    (cat=="General")?gen[def]=gen[def]"\n"$0:idi[def]=idi[def]"\n"$0
}END{
    print "General";for (g in gen) print g, gen[g]"\n-";
    print "Idioms";for (i in idi) print i, idi[i]"\n-"
}' file

输出:

General
hit 
definition 1
definition 2
-
Idioms
hit the buffers 
Definition 1
Definition 2
-
hit the sack 
Definition
-

当然,这假设您的所有定义都是“一行”

更多类别不用担心类别出现的顺序......

awk '{
    cat=$0; getline; phr=$0;getline; def=$0; getline;
    cats[cat];defs[phr]=cat;txt[phr]=txt[phr]"\n"def
}END{
    for (c in cats) {
        print c":"; for (d in defs) {
            if (defs[d]==c) print d, txt[d]"\n-"
        }
    }
}' file

输入

General
hit
Strike a blow.
-
General
hit
A successful search result. 
-
Idiom
hit the sack
Go to bed.
-
Idiom
hit the buffers
Reach the end of the line.
-
Idiom
hit the buffers
Reach the limit.
-
Bananas
Banana
A Banana

输出

Bananas:
Banana 
A Banana
-
Idiom:
hit the buffers 
Reach the end of the line.
Reach the limit.
-
hit the sack 
Go to bed.
-
General:
hit 
Strike a blow.
A successful search result. 
-

如果您想以与找到它们相同的顺序控制类别输出,那么您要么需要枚举它们,要么|为所有cats 创建一个以(例如)分隔的字符串,然后split将其放入枚举数组中,然后将其用作迭代器超过其他阵列。

这确实依赖于条目中的 4 行序列。

相关内容