Сложная часть этой проблемы заключается в том, что вы не знаете, как напечатать предыдущие значения, пока не получите следующее.
Вот скрипт, который работает разумно при подаче нескольких строк ввода, рассматривая каждую строку как отдельный набор чисел для обработки. Он полностью игнорирует пустые поля (начальные, соседние или конечные запятые). Предполагается, что поля в каждой строке все числовые и отсортированы в порядке возрастания. На самом деле он не работает с отрицательными числами в данных (форматирование с использованием тире для разделения диапазонов становится неуклюжим - но данные верны), но оно устраивает нули.
Это не самый компактный код, который возможен, но я считаю, что ясность важнее сжатия, особенно когда оно правильно (оптимизация или сжатие происходят позже, если это необходимо).
BEGIN { FS = "," }
function print_range()
{
if (lo == hi)
printf "%s%d", pad, lo
else
printf "%s%d-%d", pad, lo, hi
pad = ","
}
{
lo = ""
hi = ""
pad = ""
for (i = 1; i <= NF; i++)
{
if ($i == "") # Ignore empty fields - could report them
continue
else if (lo == "")
hi = lo = $i
else if ($i == hi + 1)
hi = $i
else
{
# Previous range complete - print it
print_range()
lo = hi = $i
}
}
print_range()
print ""
}
Я использовал файл script.awk
, содержащий приведенный выше код, и вызвал awk -f script.awk data*
для генерации вывода, показанного ниже.
Вот некоторые примерные данные (основанные на данных из вопроса):
1,3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,
1,3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53
1,3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53
3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53
3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51
Первая строка имеет запятую; другие нет. В третьей и последующих строках пропущены записи 29 и 32, поэтому в данных присутствует 2-элементный диапазон 30-31. Последние две строки имеют многоэлементный диапазон в начале вместо одного элемента; последняя строка имеет многоэлементный диапазон в конце вместо одного элемента.
Выходные данные из сценария:
1,3-9,11-13,15-51,53
1,3-9,11-13,15-51,53
1,3-9,11-13,15-28,30-31,33-51,53
3-9,11-13,15-28,30-31,33-51,53
3-9,11-13,15-28,30-31,33-51
Легко настроить печать, чтобы определить, если hi == lo + 1
, и принять решение печатать значения, разделенные запятыми, вместо значений, разделенных тире, если это предпочтительнее.