[英]Using printf, left- and right-justify two strings to a given length
在C或Bash shell中使用printf,如何將兩個字符串(字符數組)左右對齊到給定長度?
例如,如果字符串是“堆棧”和“溢出”,並且長度是20個字符,我希望打印
stack-------overflow
(為清楚起見,每個空間都顯示為破折號)。
字符串長度未知。 如果總長度+ 1超過給定的長度,是否可以從給定方向截斷一個或兩個字符串並在它們之間留一個空格? 例如,如果長度為10,我們可以得到這些嗎?
stack-over
stack-flow
s-overflow
k-overflow
我知道printf(“%10s”,string)證明右邊有一個字符串而printf(“% - 10s”,字符串)證明左邊有一個字符串,但找不到證明2個字符串對齊的方法,或者截斷他們。
這比電池更長,但是它可以更好地分割琴弦。 此外,它盡可能使用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計算的解釋。
你必須編寫自己的函數才能做到這一點。 這是一個沒有的例子和一個容易截斷的例子。 對於截斷,您需要定義一些基於截斷的規則。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void concat(const char* str1, const char* str2, char *result, int len)
{
int str1len = strlen(str1);
int str2len = strlen(str2);
memset(result, ' ', len);
if(!(str1len + str2len > len))
{
memcpy(result, str1, str1len);
memcpy(result + len - str2len, str2, str2len);
result[len] = '\0';
}
else
{
memcpy(result, str1, 1);
memcpy(result + len - str2len, str2, str2len);
result[len] = '\0';
}
}
int main()
{
char str1[] = "stack";
char str2[] = "overflow";
int len = 20;
char* result = malloc(len + 1);
int len2 = 10;
char* result2 = malloc(len2 + 1);
concat(str1, str2, result, len);
printf("%s\n", result);
concat(str1, str2, result2, len2);
printf("%s\n", result2);
free(result);
free(result2);
return 1;
}
我不認為你可以在一次操作中完成它,特別是截斷部分。 注意例如printf("%2s", "hello");
不會在C中截斷。字段寬度僅對填充目的很重要,而不是截斷。
您可能需要實現一個自定義函數來執行此操作,如下所示:
void format_pair(char *out, size_t out_max, const char *s1, const char *s2);
在Bash:
#!/bin/bash
function justify_two_strings {
a=$1; shift;
b=$1; shift;
len=$1; shift;
while [[ $(( ${#a} + ${#b} + 1 )) -gt $len ]]; do
a=${a:0:-1} # cut the last character of $a
b=${b:1} # cut the first character of $b
done
printf "%s%$(( len-${#a} ))s\n" $a $b
}
justify_two_strings 'stack' 'overflow' 20 # prints 'stack overflow'
justify_two_strings 'stack' 'overflow' 10 # prints 'sta erflow'
您可能想調整while
循環的核心,以便在不適合時縮短字符串。
一些提示:
${#a}
給出$a
的長度 ${a:s:n}
從索引s
(從0開始${a:s:n}
返回$a
n
字符。 如果省略n
,則返回所有內容,直到字符串結束。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.