用于打印的awk选择性页码
我有一个字符串,其中包含要打印的.pdf文件的页码,但我希望最小化字符串的长度,以便用破折号替换所有连续的数字,以便使用awk进行选择性打印。有谁能帮我找到awk的密码吗 从 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-13,15-51,53 试试这个:用于打印的awk选择性页码,awk,Awk,我有一个字符串,其中包含要打印的.pdf文件的页码,但我希望最小化字符串的长度,以便用破折号替换所有连续的数字,以便使用awk进行选择性打印。有谁能帮我找到awk的密码吗 从 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-13,15-51,53 试试这个
printf "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," |
awk '
function handleRange () {
if (previous == 0) {
first=$0
} else if (previous != ( $0 - 1 )) {
if ((previous - first) == 0) {
print previous
} else if ((previous - first) == 1) {
print first ORS previous
} else {
print first "-" previous
}
first=$0
}
previous=$0
}
/[0-9]/ { handleRange(); }
END { handleRange(); }
' RS=, ORS=,
输出:
1,3-9,11-13,15-51,53,
这个问题的棘手之处在于,在收到下一个值之前,您不知道如何打印上一个值 这里有一个脚本,当输入多行数据时,它可以正常工作,将每行数据作为一组单独的数字进行处理。它完全忽略空字段(前导、相邻或尾随逗号)。它假定每行上的字段都是数字,并按升序排序。它实际上不适用于数据中的负数(使用破折号分隔范围的格式变得笨拙-但数据是正确的),但它对零很满意 这并不是可能的最紧凑的代码,但我相信清晰比压缩更重要,尤其是在正确使用时(如果有必要,优化或压缩会在以后进行) 第一行后面有一个逗号;其他人没有。第三行和后续行缺少条目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
,并决定打印逗号分隔的值,而不是破折号分隔的值(如果首选)。以下是一个非常简短的awk程序,可以实现这一点:
awk 'BEGIN{FS=OFS=","}
{gsub(/,+/,","); gsub(/^,|,$/,"")}
{delete a; for(i=2;i<NF;++i) a[i]=($i-$(i-1) == 1 && $(i+1)-$i == 1)}
{for(i=1;i<=NF;++i) if (a[i]) $i=""}
{gsub(/,,+/,"-"); print}' file
{delete a; for(i=2;i<NF;++i) a[i]=($i-$(i-1) == 1 && $(i+1)-$i == 1)}
a
跟踪上一个字段的原始值,以及b
a真正的临时变量),步骤2和步骤3实际上可以组合在一起
awk'BEGIN{FS=OFS=“,”}
{gsub(/,+/,“,”);gsub(/^,|,$/,”)}
{a=$1;for(i=2;i)是在一行上显示的数字吗?它们是否用逗号分隔?如果有多行输入,是否应分别处理每行?数字是否按顺序显示(排序)?如果输入是93,96,97100
,您想要什么作为输出?您可以得到93,96-97100
或93,96,97100
。顺便说一句,10
从数据中丢失;大概预期的输出是1,3-9,11-13,15-51,53
。做得好,除非有2个数字范围(N和N+1)例如在93,96,97100
中。然后您输出输入,而不是93,96-97100
。当然,这是测试数据未涵盖的边缘情况之一,因此不清楚哪种情况是首选。我在回答中明确说明了这一点。由于您检测范围的方式,因此很难使代码适应spot 2-元素范围并将其连字号-但这可能无关紧要。我没想到代码会如此复杂,这一个很好。对于打印来说,数字之间是破折号还是逗号并不重要,只要字符串减少了这么多。@sdf可以随意接受和/或向上投票您最喜欢的任何答案。
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
awk 'BEGIN{FS=OFS=","}
{gsub(/,+/,","); gsub(/^,|,$/,"")}
{delete a; for(i=2;i<NF;++i) a[i]=($i-$(i-1) == 1 && $(i+1)-$i == 1)}
{for(i=1;i<=NF;++i) if (a[i]) $i=""}
{gsub(/,,+/,"-"); print}' file
{gsub(/,+/,","); gsub(/^,|,$/,"")}
{delete a; for(i=2;i<NF;++i) a[i]=($i-$(i-1) == 1 && $(i+1)-$i == 1)}
{for(i=1;i<=NF;++i) if (a[i]) $i=""}
{gsub(/,,+/,"-"); print}
awk 'BEGIN{FS=OFS=","}
{gsub(/,+/,","); gsub(/^,|,$/,"")}
{a=$1; for(i=2;i<NF;++i) {b=$i; $i=($i-a == 1 && $(i+1)-$i == 1) ? "" : b; a=b}}
{gsub(/,,+/,"-"); print}' file