簡體   English   中英

使用printf,左右對齊給定長度的兩個字符串

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM