Использование команды sed для диапазона чисел - PullRequest
2 голосов
/ 31 августа 2011

У меня есть файл с городом и номерами. Это CSV-файл

New York , 23456      
chicago, 123,456,789,889981(2-6)    
phoenix  123,76(0-3)    

Номер диапазона в файле, который я хочу заменить каждым номером. Например, я хочу изменить 889981 (2-6) на 8899812,8899813,8899814,8899815,8899816 и вставить в ту же строку. Смогу ли я сделать это в седе. Нужно отсканировать весь файл и сделать замену.

Ответы [ 5 ]

4 голосов
/ 31 августа 2011

sed не очень хорошо с арифметикой; Я полагаю, это не невозможно, но и не очень просто. Я бы порекомендовал использовать подходящий язык сценариев, такой как awk, perl или python (если вы не знакомы ни с одним из них, возможно, с Python; если вам нужен минимальный объем памяти, используйте awk; если вы уже знаете Perl , во что бы то ни стало, используйте Perl).

perl -pe 's/(\d+)\((\d+)-(\d+)\)$/ join (",", 
          (join ("", $1, $2) .. join ("", $1, $3))) /ge' file
2 голосов
/ 31 августа 2011

Нет, это выходит за рамки того, что вы можете сделать только с помощью регулярного выражения. Вам нужно будет добавить что-нибудь более мощное, например, perl, python или awk, или что вы чувствуете себя как дома.

1 голос
/ 31 августа 2011

Требуется gawk для функции с тремя аргументами match():

gawk '
    BEGIN {OFS = FS = ","}
    match($NF, /([0-9]+)\(([0-9]+)-([0-9]+)\)/, ary) {
        NF--
        for (n=ary[2]; n <= ary[3]; n++) {
            $(NF+1) = 10 * ary[1] + n
        }
    }
    {print}
' 

Я предполагаю (на основе выборки), что диапазон встречается только в последнем поле, разделенном запятыми.

1 голос
/ 31 августа 2011

Решение с использованием awk (@glenn jackman, вероятно, опубликует что-то, что делает это менее чем за 5 строк):

# join.awk --- join an array into a string
function join(array, start, end, sep,    result, i)
{
    if (sep == "")
       sep = " "
    else if (sep == SUBSEP) # magic value
       sep = ""
    result = array[start]
    for (i = start + 1; i <= end; i++)
        result = result sep array[i]
    return result
}


function range(input) {
    split(input, a, "[(-)]")
    # [1] is startvalue, [2] is start and stop for range
    split(a[2], b, "-")
    # [1] is start range, [2] is stop range
    # create 1st number by appending start range to start value
    c[1] = a[1] b[1]
    n=2
    for(i=b[1]; i<=b[2]; i++){
        c[n] = c[n-1] + 1
        n++
    }
    return join(c, 1, b[2], ",")

}

# a line containing a -
/-/ {
    for(i=1;i<=NF;i++){
        if ($i ~ /-/) {
        printf("%s,", range($i))
        }
        printf("%s,", $i)
    }
    print ""
}
!/-/{print}
0 голосов
/ 20 января 2012

Это может сработать для вас (только GNU sed):

sed 's/^\(.*\)\b\([0-9]\+\)(\([0-9]\)-\([0-9]\))/echo "\1" {\2\3..\2\4}/e;s/\([0-9]\),\? \([0-9]\)/\1,\2/g' file
New York , 23456      
chicago, 123,456,789,8899812,8899813,8899814,8899815,8899816
phoenix  123,760,761,762,763
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...