Bash 展开文件中的数字范围

Bash 展开文件中的数字范围,bash,shell,awk,perl,Bash,Shell,Awk,Perl,我有一个带有分隔整数的文件,我从别处提取了这些整数并将其转储到一个文件中。某些行包含一个范围,如下所示: Files 1,2,3,4,5,6,7,8,9,10 are OK Users 1,2,3-9,10 have problems Cars 1-5,5-10 are in the depot Trains 1-10 are on time 有没有办法扩展文本文件的范围,使其返回每个单独的数字,并保留分隔符?整数两边的文本可以是任何内容,我需要保留它 Files 1,2,3,4,5,6,7,

我有一个带有分隔整数的文件,我从别处提取了这些整数并将其转储到一个文件中。某些行包含一个范围,如下所示:

Files 1,2,3,4,5,6,7,8,9,10 are OK
Users 1,2,3-9,10 have problems
Cars 1-5,5-10 are in the depot
Trains 1-10 are on time
有没有办法扩展文本文件的范围,使其返回每个单独的数字,并保留分隔符?整数两边的文本可以是任何内容,我需要保留它

Files 1,2,3,4,5,6,7,8,9,10 are OK
Uses 1,2,3,4,5,6,7,8,9,10 have problems
Cars 1,2,3,4,5,6,7,8,9,10 are in the depot
Trains 1,2,3,4,5,6,7,8,9,10 are on time
我想这可以相对容易地用awk完成,更不用说任何其他脚本语言了。非常感谢您提供的任何帮助

,但我建议您在这种情况下:

perl -pe 's/(\d+)-(\d+)/join(",", $1..$2)/ge' file
这将替换所有出现的一个或多个数字,后跟连字符,后跟一个或多个数字。它使用捕获的数字创建从第一个数字到第二个数字的列表,并以逗号连接列表

此处需要
e
修饰符,以便在替换的替换部分中计算表达式

为了避免重复值并对列表进行排序,事情会变得更复杂一些。此时,我建议使用脚本,而不是一行程序:

use strict;
use warnings;
use List::MoreUtils qw(uniq);

while (<>) {
    s/(\d+)-(\d+)/join(",", $1..$2)/ge;
    if (/(.*\s)((\d+,)+\d+)(.*)/) {
        my @list = sort { $a <=> $b } uniq split(",", $2);
        $_ = $1 . join(",", @list) . $4 . "\n";
    }
} continue {
    print;
}
使用严格;
使用警告;
使用列表::MoreUtils qw(uniq);
而(){
s/(\d+)-(\d+)/加入(“,”,$1..$2)/ge;
如果(/(.*\s)((\d+,)+\d+(.*/){
my@list=sort{$a$b}uniq split(“,”,$2);
$\u=$1.join(“,”,@list)。$4.“\n”;
}
}继续{
印刷品;
}
在扩展了范围之后(就像在一行代码中),我重新解析了这行代码以提取值列表。我使用了
List::MoreUtils
(一个核心模块)中的
uniq
来删除任何重复项并对值进行排序


使用
awk
调用脚本(如
perlscript.pl文件)

解决方案:

{
    result = "";
    count = split($0, fields, /[ ,-]+/, seps);
    for (i = 1; i <= count; i++) {
        if (fields[i] ~ /[0-9]+/) {
            if (seps[i] == ",") {
                numbers[fields[i]] = fields[i];
            } else if (seps[i] == "-") {
                for (j = fields[i] + 1; j <= fields[i+1]; j++) {
                    numbers[j] = j;
                }
            } else if (seps[i] == " ") {
                numbers[fields[i]] = fields[i];
                c = asort(numbers);
                for (r = 1; r < c; r++) {
                    result = result numbers[r] ",";
                }
                result = result numbers[c] " ";
            }
        } else {
            result = result fields[i] seps[i];
        }
    }
    print result;
}
{
结果=”;
计数=拆分($0,字段,/[,-]+/,sep);
对于(i=1;i
$cat tst.awk
匹配($0,/[0-9,-]+/){
拆分(substr($0,RSTART,RLENGTH),numsIn,/,/)
numsOut=“”
删除所见
对于(i=1;i在numsIn中;i++){
n=拆分(numsIn[i],范围/-/)

对于(j=范围[1];j另一个
awk

$ awk '{while(match($0, /[0-9]+-[0-9]+/))
          {k=substr($0, RSTART, RLENGTH); 
           split(k,a,"-"); 
           f=a[1]; 
           for(j=a[1]+1; j<=a[2]; j++) f=f","j; 
           sub(k,f)}}1' file

Files 1,2,3,4,5,6,7,8,9,10 are OK
Users 1,2,3,4,5,6,7,8,9,10 have problems
Cars 1,2,3,4,5,5,6,7,8,9,10 are in the depot
Trains 1,2,3,4,5,6,7,8,9,10 are on time
$awk'{while(匹配($0,/[0-9]+-[0-9]+/)
{k=substr($0,RSTART,RLENGTH);
拆分(k,a,“-”;
f=a[1];

对于(j=a[1]+1、 这个问题以前有人问过,但我没有找到链接,同时,你是对的,这可以由awk完成,你做了多少?我在这里没有看到一个问题…关于要求,重叠会发生在两个范围上吗?范围总是分类的吗?你需要一个通用的解决方案,或者只是为了一些特定的输入?我可以同样的答案。我在尝试东西时发现了一些奇怪的东西。如果我做了
perl-pe的/(\d+)-(\d+)/print$1..$2/ge'
,它会在行首之前打印数字。知道为什么吗?@123是的,因为你正在评估一个
print
命令(直接到stdout)。但这会产生重复的索引。非常感谢。这很好。完全没有perl技能-我已经对其进行了修改,使其只拾取带有特定字符串的行。似乎与sed的语法类似,也许我应该用perl钻研一下。@captainyossarian是的,正则表达式匹配或替换的语法与sed类似,但功能更强ful。您可以将内容分配给变量,这很方便;)
$ awk '{while(match($0, /[0-9]+-[0-9]+/))
          {k=substr($0, RSTART, RLENGTH); 
           split(k,a,"-"); 
           f=a[1]; 
           for(j=a[1]+1; j<=a[2]; j++) f=f","j; 
           sub(k,f)}}1' file

Files 1,2,3,4,5,6,7,8,9,10 are OK
Users 1,2,3,4,5,6,7,8,9,10 have problems
Cars 1,2,3,4,5,5,6,7,8,9,10 are in the depot
Trains 1,2,3,4,5,6,7,8,9,10 are on time