这比电池长,但恕我直言,它可以更好地分开琴弦。它还在可能的情况下使用 printf 进行截断,仅针对第二个参数的左手截断回退到其他机制。
重击:
truncat () {
local len=$1 a=$2 b=$3 len_a=${#2} len_b=${#3}
if ((len <= 0)); then return
elif ((${len_b} == 0)); then
printf %-${len}.${len}s "$a"
elif ((${len_a} == 0)); then
printf %${len}.${len}s "${b: -$((len<len_b?len:len_b))}"
elif ((len <= 2)); then
printf %.${len}s "${a::1}${b: -1}"
else
local adj_a=$(((len_a*len+len_b-len_a)/(len_a+len_b)))
local adj_b=$(((len_b*len+len_a-len_b-1)/(len_a+len_b)))
printf "%-${adj_a}.${adj_a}s %${adj_b}.${adj_b}s" \
"$a" \
"${b: -$((len_b<adj_b?len_b:adj_b))}"
fi
}
C:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void truncat(long len, const char* a, const char* b) {
if (len <= 0) return;
unsigned long long len_a = strlen(a);
unsigned long long len_b = strlen(b);
if (!len_b)
printf("%-*.*s", (int)len, (int)len, a);
else if (!len_a)
printf("%*s", (int)len, b + (len < len_b ? len_b - len : 0));
else if (len <= 2)
printf("%.1s%.*s", a, (int)(len - 1), b + len_b - 1);
else {
unsigned long long adj_a = (len_a * len + len_b - len_a) / (len_a + len_b);
unsigned long long adj_b = (len_b * len + len_a - len_b - 1) / (len_a + len_b);
printf("%-*.*s %*s",
(int)adj_a, (int)adj_a, a,
(int)adj_b, b + (adj_b < len_b ? len_b - adj_b : 0));
}
}
int main(int argc, char** argv) {
truncat(atol(argv[1]), argv[2], argv[3]);
return 0;
}
样本输出:
$ for i in {0..20}; do printf "%2d '%s'\n" $i "$(./truncat $i stack overflow)"; done
0 ''
1 's'
2 'sw'
3 's w'
4 's ow'
5 'st ow'
6 'st low'
7 'st flow'
8 'sta flow'
9 'sta rflow'
10 'stac rflow'
11 'stac erflow'
12 'stac verflow'
13 'stack verflow'
14 'stack overflow'
15 'stack overflow'
16 'stack overflow'
17 'stack overflow'
18 'stack overflow'
19 'stack overflow'
20 'stack overflow'
免责声明:算术可能会溢出,在这种情况下输出将是错误的(或者,如果您可以将 strlen(a)+strlen(b) 安排为正好 2^64 字节,则程序将 SIG_FPE)。如果有人关心,我可以为 adj_a 和 adj_b 计算提供解释。