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

时间:2017-10-10 07:16:26

标签: bash shell awk sed grep

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

例如

项目清单

cat item.txt
    sn01
    sn02
    sn03
    sn05
    sn07
    sn08

期望的输出

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

4 个答案:

答案 0 :(得分: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]

答案 1 :(得分:1)

  

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

使用 var list = new int[] { 4,5,6}; var whereFunction = new Interpreter() .SetVariable("mylist", list) .Reference(typeof(ExtensionMethods)); whereFunction.ParseAsExpression<Func<Person, bool>>("(person.Age == 5 && person.Name.StartsWith(\"G\")) || person.Age == 3 && mylist.Exists(person.Id)", "person"); // Define this class somewhere public static class ExtensionMethods { public static bool Exists<T>(this IEnumerable arr, T searchKey) { return ((IEnumerable<T>)arr).Contains(searchKey); } }

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]

答案 2 :(得分:1)

一个简单的 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

答案 3 :(得分:0)

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]