【问题标题】:How would I fix the alignment on this Table?我将如何修复此表上的对齐方式?
【发布时间】:2021-11-08 07:52:33
【问题描述】:

我已经用 C 编写了这个程序,它读取一个文件并将其打印到一个与垂直条对齐的表格中,包括标题和足迹。该文件始终有 3 列,但行数不同。这些列的字符数量会有所不同。我遇到的问题是,我读入的第一个文件完全对齐,但是当我读入其他所有列中尺寸增加的文件时,它没有对齐。有没有办法让它自动对齐,还是我每次都必须手动执行?

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// constant to store the maximum size of the records that can be read from the file

enum
{
    // update MAX_SIZE to if the number of rows is more than 1000
    MAX_SIZE = 1024
};

// structure to store a record from the file
typedef struct
{
    char define[20];
    char octal[26];
    char description[1000];
} Record;

// string to store the header of the table
char header1[20], header2[20], header3[20];

// function to read the file and return the maximum length of the descriptions read from the file
int readFile(Record rec[], int *size)
{
    // open a file for input
    FILE *fp = fopen("input2.txt", "r");

    // check if the file opened successfully
    if (fp == NULL)
    {
        printf("File could not be opened!");
        exit(1);
    }

    int i = 0;
    int maxLength=0;
    // read the file
    // first we read the header of each column from the file
    fscanf(fp, "%s %s %s\n", header1, header2, header3);

    // now we read each record from the file
    while (fscanf(fp, "%19s ", rec[i].define) == 1) 
    {
        fscanf(fp, "%10s '%[^']'", rec[i].octal, rec[i].description);

        // find the length of the description and update the 'maxLength'
        if (strlen(rec[i].description) > maxLength) 
        {
            maxLength = strlen(rec[i].description);
        }

        // increment the value of i
        i++;
    }
    
    // close the input file
    fclose(fp);

    // update the number of records read from the file
    *size = i;

    return maxLength;
}

void printTable(Record rec[], int size, int WIDTH)
{
    char p='|';
    // print the header of the table
    for (int i = 0; i < 22 + WIDTH; i++)
        printf("-");

    printf("\n| %-7s %c %5s %c %-*s %c\n", header1, p, header2, p, WIDTH, header3,p);

    for (int i = 0; i < 22 + WIDTH; i++)
        printf("-");

    printf("\n");

    // print the table data
    for (int i = 0; i < size; i++)
        printf("| %-7s | %5s | %-*s |\n", rec[i].define, rec[i].octal, WIDTH, rec[i].description);

    // print the footer
    for (int i = 0; i < 22 + WIDTH; i++)
        printf("-");

    printf("\n");
}

// driver function
int main()
{
    // create an array of recors of MAX_SIZE
    Record recs[MAX_SIZE];
    // initialize size of recs to zero
    int size = 0;

    // call readFile() function to read data from the file and update the size of recs
    int WIDTH = readFile(recs, &size);
    // call printTable() function to print the table in a well-formatted manner
    printTable(recs, size, WIDTH);

    return 0;
}

文件:

#define octal description
O_APPEND 02000 'The file is opened in append mode.'
O_ASYNC 020000 'Enable signal-driven I/O.'
O_CLOEXEC 02000000 'Enable the close-on-exec flag for the new file descriptor.'
O_CREAT 0100 'If pathname does not exist, create it as a regular file.'
O_DIRECT 040000 'Try to minimize cache effects of the I/O to and from this file.'
O_DIRECTORY 0200000 'If pathname is not a directory, cause the open to fail.'
O_DSYNC 010000 'Write operations will complete according to the requirements of synchronized I/O data integrity completion.'
O_EXCL 0200 'Ensure that this call creates the file.'
O_LARGEFILE 0 'Allow files whose sizes cannot be represented in an off_t to be opened.'
O_NOATIME 01000000 'Do not update the file last access time (st_atime in the inode) when the file is read(2).'
O_NOCTTY 0400 'If pathname refers to a terminal device it will not become the processs controlling terminal.'
O_NOFOLLOW 0400000 'If pathname is a symbolic link, then the open fails, with the error ELOOP.'
O_NONBLOCK 04000 'When possible, the file is opened in nonblocking mode.'
O_PATH 010000000 'Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level.'
O_SYNC 04010000 'Write operations will complete according to the requirements of synchronized I/O file integrity completion.'
O_TMPFILE 020200000 'Create an unnamed temporary regular file.'
O_TRUNC 01000 'If the file already exists and is a regular file it will be truncated to length 0.'

当前正在打印的内容:

---------------------------------------------------------------------------------------------------------------------------------
| #define | octal | description                                                                                                 |
---------------------------------------------------------------------------------------------------------------------------------
| O_APPEND | 02000 | The file is opened in append mode.                                                                          |
| O_ASYNC | 020000 | Enable signal-driven I/O.                                                                                   |
| O_CLOEXEC | 02000000 | Enable the close-on-exec flag for the new file descriptor.                                                  |
| O_CREAT |  0100 | If pathname does not exist, create it as a regular file.                                                    |
| O_DIRECT | 040000 | Try to minimize cache effects of the I/O to and from this file.                                             |
| O_DIRECTORY | 0200000 | If pathname is not a directory, cause the open to fail.                                                     |
| O_DSYNC | 010000 | Write operations will complete according to the requirements of synchronized I/O data integrity completion. |
| O_EXCL  |  0200 | Ensure that this call creates the file.                                                                     |
| O_LARGEFILE |     0 | Allow files whose sizes cannot be represented in an off_t to be opened.                                     |
| O_NOATIME | 01000000 | Do not update the file last access time (st_atime in the inode) when the file is read(2).                   |
| O_NOCTTY |  0400 | If pathname refers to a terminal device it will not become the processs controlling terminal.               |
| O_NOFOLLOW | 0400000 | If pathname is a symbolic link, then the open fails, with the error ELOOP.                                  |
| O_NONBLOCK | 04000 | When possible, the file is opened in nonblocking mode.                                                      |
| O_PATH  | 010000000 | Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level.  |
| O_SYNC  | 04010000 | Write operations will complete according to the requirements of synchronized I/O file integrity completion. |
| O_TMPFILE | 020200000 | Create an unnamed temporary regular file.                                                                   |
| O_TRUNC | 01000 | If the file already exists and is a regular file it will be truncated to length 0.                          |
---------------------------------------------------------------------------------------------------------------------------------

它应该是什么样子:

-----------------------------------------------------------------------------------------------------------------------------------------
| #define     |     octal | description                                                                                                 |
-----------------------------------------------------------------------------------------------------------------------------------------
| O_APPEND    |     02000 | The file is opened in append mode.                                                                          |
| O_ASYNC     |    020000 | Enable signal-driven I/O.                                                                                   |
| O_CLOEXEC   |  02000000 | Enable the close-on-exec flag for the new file descriptor.                                                  |
| O_CREAT     |      0100 | If pathname does not exist, create it as a regular file.                                                    |
| O_DIRECT    |    040000 | Try to minimize cache effects of the I/O to and from this file.                                             |
| O_DIRECTORY |   0200000 | If pathname is not a directory, cause the open to fail.                                                     |
| O_DSYNC     |    010000 | Write operations will complete according to the requirements of synchronized I/O data integrity completion. |
| O_EXCL      |      0200 | Ensure that this call creates the file.                                                                     |
| O_LARGEFILE |         0 | Allow files whose sizes cannot be represented in an off_t to be opened.                                     |
| O_NOATIME   |  01000000 | Do not update the file last access time (st_atime in the inode) when the file is read(2).                   |
| O_NOCTTY    |      0400 | If pathname refers to a terminal device it will not become the processs controlling terminal.               |
| O_NOFOLLOW  |   0400000 | If pathname is a symbolic link, then the open fails, with the error ELOOP.                                  |
| O_NONBLOCK  |     04000 | When possible, the file is opened in nonblocking mode.                                                      |
| O_PATH      | 010000000 | Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level.  |
| O_SYNC      |  04010000 | Write operations will complete according to the requirements of synchronized I/O file integrity completion. |
| O_TMPFILE   | 020200000 | Create an unnamed temporary regular file.                                                                   |
| O_TRUNC     |     01000 | If the file already exists and is a regular file it will be truncated to length 0.                          |
-----------------------------------------------------------------------------------------------------------------------------------------

【问题讨论】:

  • "| %-12s | %9s | %-*s |\n"
  • 我知道如何手动完成。问题是当尺寸发生变化时,我需要它来自动格式化。
  • 听起来您需要在开始打印之前遍历表格的内容并计算每列的最大宽度。
  • 如果我要找到这个,我怎么能把那个数字放在 %s 前面?
  • 您已经有代码可以在读取描述字段时找到其最大长度,以及适应该字段打印的代码。将其扩展到其他两个领域有什么问题?它们可以用相同的方式测量和格式化。宽度不能作为单个数字从 readFile 返回,但有多种选择。

标签: c file printf alignment


【解决方案1】:

考虑一个实现相同目标的人为示例。

#include <stdio.h>
#include <string.h>

struct ContrivedData {
    char a[100];
    char b[100];
    char c[100];
};

int main(void) {
    struct ContrivedData cd1 = {"Hello", "world", "!"};
    struct ContrivedData cd2 = {"foo", "bar", "baz"};
    struct ContrivedData cd[2];

    cd[0] = cd1;
    cd[1] = cd2;

    int cd_len = sizeof(cd) / sizeof(*cd);
    
    int max_a_len = 0;
    int max_b_len = 0;
    int max_c_len = 0;

    for (int i = 0; i < cd_len; i++) {
        int a_len = strlen(cd[i].a);
        if (a_len > max_a_len) {
            max_a_len = a_len;
        }

        int b_len = strlen(cd[i].b);
        if (b_len > max_b_len) {
            max_b_len = b_len;
        }

        int c_len = strlen(cd[i].c);
        if (c_len > max_c_len) {
            max_c_len = c_len;
        }
    }

    for (int i = 0; i < cd_len; i++) {
        printf("%-*s | %-*s | %-*s\n", 
               max_a_len, cd[i].a, 
               max_b_len, cd[i].b, 
               max_c_len, cd[i].c);
    }

    return 0;
}

在打印数据之前,我遍历数组并计算每个字段的最大宽度。根据数据的类型,您可能需要使用strlen以外的某些功能。

我得到的结果是:

% ./test2
Hello | world | !  
foo   | bar   | baz

如果我稍微改变一下数据,你可以看到它仍然保持对齐。

% ./test2
Hello | world     | !  
foo   | barbarbar | baz

【讨论】:

    【解决方案2】:

    示例函数。

    struct a 
    {
        char *s ; int x; char *y;
    } a[] = {
        {"Hello", 435342435432, "1"},
        {"dfgsfdgdgdfgdf", 5, "1fdsfsdfs"},
        {"Hellodfds", 43534, "sdffs"},
        {"H", 2435432, "1dfdsfdsfsdd"},
        {NULL,}
    };
    
    
    void print(struct a *data)
    {
        int widths[3] = {0};
        struct a *wrk;
        size_t len;
    
        for(wrk = data; wrk -> s; wrk++)
        {
            if((len = strlen(wrk -> s)) > widths[0]) widths[0] = len;
            if((len = strlen(wrk -> y)) > widths[2]) widths[2] = len;
            if((len = snprintf(NULL, 0, "%d", wrk -> x)) > widths[1]) widths[1] = len;
        }
        for(wrk = data; wrk -> s; wrk++)
        {
            printf("| %-*s | %*d | %*s |\n", widths[0], wrk -> s , widths[1], wrk -> x,  widths[2], wrk -> y);
        }
    }
    

    输出:

    | Hello          | 1550738536 |            1 |
    | dfgsfdgdgdfgdf |          5 |    1fdsfsdfs |
    | Hellodfds      |      43534 |        sdffs |
    | H              |    2435432 | 1dfdsfdsfsdd |
    

    【讨论】:

    • 感觉这可以使用更多的解释,而不是仅仅一段代码,而且没有cmets。
    猜你喜欢
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 2021-01-14
    • 2019-07-06
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多