これはバッテリーよりも長いですが、それは文字列をよりよく分割します。また、可能な場合はprintfを使用して切り捨てを行い、2番目の引数の左側の切り捨てに対してのみ他のメカニズムにフォールバックします。
バッシュ:
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の計算について説明することができます。