You’re right! Thanks, nutilius. I thought I’d tried it without braces, but clearly I hadn’t. I think the braces make the code look clearer in a one-liner, but that’s a separate issue. ![]()
OK - I know that this is “private investigation”
, but here is my proposal (in Python):
#!/usr/bin/env python3
s = '10, 23, 15-16, 1, 38-40, 4-5, 39-41, 44, 51' # , 8-19'
print(s)
# Find max page
m = int(max(s.replace('-', ', ').replace(', ', ',').split(','), key=int))
# Page map - present pages as '*'
pages = list((m + 1) * " ")
for v in s.replace(' ', '').split(','):
try:
# Fill spanned area
(b, e) = v.split('-')
for i in range(int(b), int(e)+1): pages[i] = '*'
except:
# Sorry there is only one
pages[int(v)] = '*'
# Remove 0-based index artefact and convert to string
pages = "".join(pages[1:]) + " "
# Result accumulated in string to cutoff last comma
result = ""
p = pages.find('*', 0)
q = pages[p:].find(' ')
while p >= 0:
#print(f"==>{p=} {q=}")
if q == 1:
result += f"{p+1},"
else:
result += f"{p+1}-{p+q},"
p = pages.find('*', p+q)
q = pages[p:].find(' ')
# Cut-off last comma
print(result[:-1])
I’m sorry but the last solution in bash doesn’t work with unsorted or overlapped sequences
, like for example:
1 2 3 4 6-8 8 10 12 13 2 37-39 14 17 18-20 21-22 23 35-39 99 100 101
Hi nutilius.
If you mean the script doesn’t integrate duplicates and out-of-order numbers with the others as a single set of numbers and ranges, it’s not meant to. For reasons of his own, peavine wanted the page order and duplicates to be preserved. (See post 8 above.)
Mhm my mistake, I didn’t read carefully. So I will save my solution for other situations, maybe somewhere will be usable.
Just for learning purposes, I edited Nigel’s shell script to work with the Zsh shell. First, I substituted -A for -a as a read command option. Second, I made those changes necessary to work with 1- instead of 0-based arrays. I did not edit the test equality operators, because the script seemed to work without this change, and I wasn’t sure if the test should be for string or numeric equality (both seem to work).
#!/bin/zsh
read -A input_array <<< "1 2 3 4 6-8 8 10 12 13 2 14 17 18-20 21-22 23"
input_count=${#input_array[@]}
item=${input_array[1]} # array is 1-based
range_start=${item%%-*}
range_end=${item#*-}
for (( i=2; $i <= $input_count; i++ )); do
item=${input_array[i]}
pn1=${item%%-*}
pn2=${item#*-}
if [[ $((range_end + 1 )) == $pn1 ]]; then # tests for string equality
range_end=$pn2
else
new_item=$range_start
if [[ $range_end != $range_start ]]; then # tests for string inequality
new_item+="-$range_end"
fi
output+="$new_item "
range_start=$pn1
range_end=$pn2
fi
done
new_item=$range_start
if [[ $range_end != $range_start ]]; then
new_item+="-$range_end"
fi
output+="$new_item"
printf "$output"
# For testing if swiftDialog app installed
# dialog --title "Script Test" --titlefont "size=15" --message "$output" --messagefont "size=13" --messageposition bottom --width 300 --height 150 --hideicon
I also tested without issue in a shortcut:
Zsh Shell Script.shortcut (21.9 KB)
I ran timing tests and there were no differences between the Bash and Zsh scripts.