【问题标题】:how to group sequence of item into square brackets如何将项目序列分组到方括号中
【发布时间】:2017-10-10 07:16:25
【问题描述】:

如何将项目序列分组到方括号中

例如

项目列表

cat item.txt
    sn01
    sn02
    sn03
    sn05
    sn07
    sn08

期望的输出

sn[01-03,05,07-08]

【问题讨论】:

  • 你做了哪些努力?向我们展示您的尝试
  • 数字总是按顺序排列的吗?

标签: bash shell awk sed grep


【解决方案1】:

如果您的数据与所示的 Input_file 示例相同,那么以下内容可能对您有所帮助。

awk 'FNR==1{line=$0} {sub(/[a-z]+/,"")} $0-val>1 && val1!=val{out=out?out "," val1"-"val:line"[" val1"-"val;val1=$0} $0-val>1 && val1==val{out=out?out "," val1:out "," val1;val1=$0} {if(FNR==1){sub(/[0-9]+/,"",line);val1=$0};val=$0}END{if(val1!=val){print out "," val1"-"val"]"} else {print out "," val"]"}}'  Input_file

也添加非单线形式的解决方案。

awk '
FNR==1{
  line=$0
}
{
sub(/[a-z]+/,"")
}
$0-val>1 && val1!=val{
  out=out?out "," val1"-"val:line"[" val1"-"val;
  val1=$0
}
$0-val>1 && val1==val{
  out=out?out "," val1:out "," val1;
  val1=$0
}
{
if(FNR==1){
  sub(/[0-9]+/,"",line);
  val1=$0
};
val=$0
}
END{
if(val1!=val){
  print out "," val1"-"val"]"
}
else{
  print out "," val"]"
}
}
'    Input_file

输出如下。

sn[01-03,05,07-08]

【讨论】:

  • "sn" 在这里是静态的。它应该从输入文件中选择它。当我给出以“cn”开头的项目列表时。它仍然选择“sn”
  • sn[01-31,50-51,82-85,100-100] “100”也出现两次
  • @asokan,您能否现在检查我的编辑,如果这对您有帮助,请告诉我?
  • @asokan,很高兴对你有所帮助,继续学习,继续分享,干杯。
【解决方案2】:

“sn”在这里是静态的。它应该从输入文件中选择它。当我 给定的项目列表以“cn”开头。它仍然选择“sn”

使用awk

$ cat infile
sn01
sn02
sn03
sn05
sn07
sn08
cn08
cn09
cn10
cn11
cn15

search='sn'

$ awk -v search='sn' 'function pr(){if(f && l)printf("%s%s",n?",":search"[",f==l?f:f"-"l)}$0!~"^"search{next}{t=$1;sub(/[^0-9]+/,"",t)}f==""{f=l=t;next}t==l+1{l=t;next}{pr();f=l=t;n++}END{pr(); print n?"]":"Nothing matched for keyword :"search}' infile
sn[01-03,05,07-08]

search='cn'

$ awk -v search='cn' 'function pr(){if(f && l)printf("%s%s",n?",":search"[",f==l?f:f"-"l)}$0!~"^"search{next}{t=$1;sub(/[^0-9]+/,"",t)}f==""{f=l=t;next}t==l+1{l=t;next}{pr();f=l=t;n++}END{pr(); print n?"]":"Nothing matched for keyword :"search}' infile
cn[08-11,15]

更好的可读性:

awk -v search='sn' '
                   function pr()
                   {
                       if(f && l)
                         printf("%s%s",n?",":search"[",f==l?f:f"-"l)
                   }
                   $0!~"^"search{ 
                          next 
                   }
                   {
                         t=$1;
                         sub(/[^0-9]+/,"",t)
                   }
                  f==""{
                         f=l=t;
                         next
                   }
                   t==l+1{
                         l=t;
                         next
                   }
                   {
                         pr();
                         f=l=t;
                         n++
                   }
               END{
                         pr(); 
                         print n?"]":"Nothing matched for keyword :"search
                  }' infile

【讨论】:

    【解决方案3】:

    一个简单的awk解决方案

    我们的目标是为每个可能的范围设置 LBUB
    LB 开始,common difference 为 1 的最后一个数字给了我们UB
    如果差异大于1,则打印最后一个范围并再次设置LB

    $ awk 'FNR==1{ $1=$1; prefix=substr($0,1,2);} {gsub(/[^0-9]/,"",$1); a[++i]=$1;} END{ printf prefix"["; LB=UB=prev=a[1]; for(i=1; i<=NR; i++){ if(int(a[i+1])==int(prev+1)) { UB=a[i+1]; prev=UB; } else { if(LB==UB) { printf LB"," } else {delim=(i==NR)? "]" :","; printf LB "-" UB delim; } prev=LB=UB=a[i+1]; }} }' file
    
    sn[01-03,05,07-08]
    

    gsub(/[^0-9]/,"",$1) :这会将所有非数字字符设置为空。因此$1 以数字结束;

    为了更好地理解它:

    $ awk 'FNR==1{ $1=$1; prefix=substr($0,1,2); } {gsub(/[^0-9]/,"",$1); a[++i]=$1;} 
        END
        { 
            printf prefix"["; LB=UB=prev=a[1]; 
    
            for(i=1; i<=NR; i++)
            { 
                if(int(a[i+1])==int(prev+1)) 
                { 
                    UB=a[i+1]; 
                    prev=UB; } 
    
                else 
                { 
                    if(LB==UB) 
                    { 
                        printf LB"," 
                    } 
    
                    else 
                    {   
                        delim=(i==NR)? "]" :","; 
                        printf LB "-" UB delim; 
                    } 
    
                    prev=LB=UB=a[i+1]; 
                }
            } 
        }' file
    

    【讨论】:

    • 是的,有道理!! (y) 谢谢阿克谢。让我更新一下。
    【解决方案4】:

    Awk解决方案:

    awk '{ v=substr($0,3) }NR==1{ pfx=substr($0,1,2); r=a=v; next }
         { diff=v-a; if(diff>1) { r=r ((a==last)? ",":"-"a",")v; last=v } a=v }
         END{ if(diff==1) r=r"-"v; print pfx"["r"]" }' file
    

    输出:

    sn[01-03,05,07-08]
    

    【讨论】:

      猜你喜欢
      • 2021-11-07
      • 2019-02-27
      • 2020-05-30
      • 2019-06-11
      • 1970-01-01
      • 2019-01-01
      • 1970-01-01
      • 2020-07-17
      • 1970-01-01
      相关资源
      最近更新 更多