gpt4 book ai didi

c - 根据输入来格式化文本文件

转载 作者:行者123 更新时间:2023-11-30 15:16:22 25 4
gpt4 key购买 nike

我正在为一个学校项目工作,但遇到了一些麻烦。该项目的要旨是编写一个程序,该程序读取文本文件并格式化该文件,以使其适合特定的宽度。要格式化该文件,用户需要指定输入文件,输出行的长度以及输出文本的理由。一个例子是这样的:

$ ./format test.dat 15 rightThe quick brown fox jumps over   the lazy old           dog.$ ./format test.dat 15 leftThe quick brownfox jumps overthe lazy olddog.$ ./format test.dat 15 centerThe quick brownfox jumps over the lazy old     dog.

Anyway, I am basically stuck on how to go about outputting the file based on this. Attached below is my code for reading in the file, and what little I have done on outputting the file. I am mainly looking for tips or suggestions on how to go about doing it. I know I need to use printf with a width and such, but I am confused on how to move to the next line.

char **inputFile(FILE *fp, int size) {
int i = 0;
char *token;
char **str;
str = malloc(sizeof(char *) * size);
token = readToken(fp);
while(!feof(fp)) {
if(i+1 == size) {
realloc(str, size * 2);
}

str[i] = token;
token = readToken(fp);
i++;
}
return str;
}

void toPrint(char **string, int width, int indent) {
int i;
int curLineLength;
if(indent == 0) {
for(i = 0; I < strlen(string); i++
char *token = string[i];
if(curLineLength + strlen(*string) > width) {
if(curLineLength > 0) {
printf("\n");
curLineLength = 0;
}
}
printf("%s ", token);
curLineLength += strlen(*string);
}
/*
if(indent == 1) {

}
if(indent == 2) {

}
*/
}

最佳答案

从注释开始,证明行对齐的任务比构造输出函数更多的是逻辑挑战,而不是困难的挑战。你越来越近了。有很多方法可以做到,您可能需要添加错误检查以确保width不小于最长的行。

这是您可以借鉴的简单示例。确保您了解每行的编写方式,并密切注意可变长度数组的定义(您将需要编译为c99-或如果使用gcc,则依赖gcc扩展名(默认))。如果您有任何问题,请告诉我:

/*  format 'n' lines of output of 't' justified as specified in 'just'
(left 'l', right 'r' or centered 'c') within a width 'w'.
NOTE: 'w' must be larger than the longest line in 't'.
*/
void formatted (char **t, char just, size_t w, size_t n)
{
if (!t || !*t) return;
size_t i = 0;
size_t lmax = 0;
size_t len[n];

/* calculate the length of each line, set lmax */
for (i = 0; i < n; i++) {
len[i] = strlen (t[i]);
if (len[i] > lmax) lmax = len[i];
}

/* handle w < lmax reformat or error here */
if (w < lmax) {
fprintf (stderr, "%s() error: invalid width < lmax (%zu).\n",
__func__, lmax);
return;
}

/* left justified output */
if (just == 'l') {
for (i = 0; i < n; i++) {
printf ("%s\n", t[i]);
}
return;
}

/* center or right justified output */
for (i = 0; i < n; i++) {
int spaces = w - len[i];
if (just == 'c')
printf ("%*s%s\n", spaces/2, " ", t[i]);
else if (just == 'r')
printf ("%*s%s\n", spaces, " ", t[i]);
}
}


注意:如果您使用的是Windows,请在每个错误语句中将 __func__更改为函数名称。

功能逻辑-长版

让我们再仔细看看该函数的功能以及为什么这样做。首先,让我们看一下所需的参数:

void formatted (char **t, char just, size_t w, size_t n)


char **t,您的“字符串”,嗯……实际上是您键入 char*的数组或指针。当您将指针数组传递给函数时,这可能就是您的困惑所在,您只有两种方法可以遍历数组,在每一行文本中进行打印:(1)传递指向该指针的有效指针数到包含文本的字符串,或(2)在数组内提供一个由指向最后一个指向文本有效行的指针所指向的指针。 (通常只是 NULL)前哨充当数组中的指针,告诉您(“假人,停止尝试打印行-您已经打印了最后一行...”)

这需要更多解释。考虑一下内存中的指针数组。通常,您总是会分配一些合理预期的指针数来填充,并且当您填充最后一个指针时,您将 realloc数组包含更多空间。这意味着您在未填充数组的末尾将始终至少有1个指针。如果要在一开始就初始化数组以包​​含 NULL指针(通过使用 calloc而不是 malloc进行分配)-您将自动提供一个前哨,或者,您始终可以将下一个指针显式设置为 填充数组时。这将使您的char *指针数组看起来类似于以下内容:

  Pointer         The pointers in the array of pointers to char*, char **t;
Address point to the first character in each associated string.
+-----------+
| 0x192a460 | --> The quick brown
+-----------+
| 0x192a480 | --> fox jumps over
+-----------+
| 0x192a4a0 | --> a lazy
+-----------+
| 0x192a4c0 | --> dog.
+-----------+
| NULL |
+-----------+
| NULL |
+-----------+
...


了解:您的 NULL,我的 stringt而不是字符串本身。您的 array of pointers to type char*是上方指针的左列。 string是每个真实字符串的起始地址的数组,而您的 string将是实际字符串本身的起始-在该地址。 string[i]的范围为 i(总计 0-3),其中 4string[0] = "The quick brown"等。要获得帮助,请将您的 string[1] = "fox jumps over"代码中的名称更改为 stringarray以提供帮助保持直率。

您遍历数组以打印每个字符串的2个选项变为(1)(将大小为'n'传递给函数):

for (i = 0; i < n; i++)
printf ("%s\n", t[i]);


或(2)(依靠哨兵):

while (t[i]))
printf ("%s\n", t[i++]);


(虽然在这里并不很明显,但是随着代码变得更加复杂,并且需要在许多不同的函数之间传递数组,这将带来巨大的好处)

既然您知道如何访问每个字符串,那么从只打印左对齐的字符串开始。您不在乎长度,也不在乎宽度(只要您的字符串适合 str_array即可)。您需要做的就是打印每个字符串。由于我们将字符串 width的数量传递给函数,因此我们可以简单地使用 'n'循环(方法1)来打印每个字符串。 (长度是在打印之前计算出来的,以确保每个字符串都适合 for,因为我们稍后将使用它,因此我们将每个长度存储在可变长度数组 width中,因此我们不必对< cc>稍后)

更有趣的情况是 lenstrlen合理的情况。除了“ n”之外,您还需要知道用户想要的理由。您可以传递要将该信息传递给函数的任何类型标志。 centerright)只是最有效的,并且在读取为程序输入时不需要转换为数字。从本质上讲,这就是为什么我选择将 char作为 1-byte而不是 justchar +输入转换)(或 int4-bytes)等)传递的原因。

首先让我们看一下如何对输出进行右对齐。为了讨论起见,让我们考虑要在其中右对齐字符串的 short个字符的输出宽度。您的第一个字符串是 2-bytes(可打印的)字符长(由于 20,它实际上在内存中是 15字符)字符末)。让我们直观地看到我们的可打印字符字符串在20个字符的缓冲区中的样子(您将使用该字符将字符串的右对齐副本保存在内存中,而不是进行打印)

|<-------  20 character width  -------->|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | |T|h|e| |q|u|i|c|k| |b|r|o|w|n|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|<-- 15 character length -->|


这使得在开始打印字符串之前很容易看到需要多少空间。这里的任务是将其转换为通用代码,以处理任何长度的字符串。不太困难:

spaces = width - length;


然后,为了利用它来打印右对齐的字符串,我们使用 16格式字符串中的 null-terminating指令。在此特别有用的功能是可以在 minimum field width参数列表中将字段宽度指令指定为变量。构造格式字符串和参数列表以实现我们的目标,我们有:

printf ("%*s%s\n", spaces, " ", t[i]);


也就是说,为字符串 printf打印最小字段宽度 printf(本质上会打印 spaces空格-名称选择不佳),然后是指针数组 " "中的实际字符串。

再次查看该图,我们要怎么做才能将字符串移到20个字符的宽度的中心?只能将 spaces移位很多,而不能将整个 t[i]的空格都切掉,最终它将移到我们想要的位置。 (我能听到您的头在打磨齿轮,还能闻到烟雾的味道-“但是,等等... width - length是一个奇数,我们正在使用整数!”-没关系,整数除法会好好处理的,如果我们将2而不是2.5移位,那就很好了,您将不能打印1/2个字符...因此,将它们放在一起以处理居中或右对齐的文本,您所需的全部是:

for (i = 0; i < n; i++) {
int spaces = w - len[i];
if (just == 'c')
printf ("%*s%s\n", spaces/2, " ", t[i]);
else if (just == 'r')
printf ("%*s%s\n", spaces, " ", t[i]);
}


将所有内容与其余内容放在一起

有时,了解整个事物如何组合会有所帮助。相同的规则。逐个功能逐行浏览,并在遇到问题时提出问题。 C是一种低级语言,这意味着您必须了解事物在内存中的位置。归根结底,编程实际上是关于如何操纵加载到内存中的内容。其他语言则试图将其隐藏起来。 C没有。这是它的优势,也是您必须集中精力学习的大部分内容。 ba不休,下面是代码:

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

#define MAXC 256
#define MAXL 64

char **inputfile (char ***t, FILE *fp, size_t *sz);
void formatted (char **t, char just, size_t w, size_t n);
void *xcalloc (size_t n, size_t s);
void freecdp (char **p, size_t n);
unsigned chr2lower (unsigned c);

int main (int argc, char **argv) {

if (argc < 4) { /* validate required arguments on command line */
fprintf (stderr, "error: insufficient input. "
"usage: %s just width [filename (stdin)]\n",
argv[0]);
return 1;
}

char **text = NULL; /* initialize all variables for main */
size_t lines = 0;
char j = 0; /* the following are ternary operators */
char just = argc > 1 ? *argv[1] : 'l'; /* sets defaults if no input */
size_t width = argc > 2 ? (size_t)strtol (argv[2], NULL, 10) : 0;
FILE *fp = argc > 3 ? fopen (argv[3], "r") : stdin;

/* read input from file */
if (!(inputfile (&text, fp, &lines))) { /* check if return is NULL */
fprintf (stderr, "error: file read failed '%s'.\n",
argc > 3 ? argv[3] : "stdin");
return 1;
}

j = chr2lower (just); /* force user input to lower-case */
if (j != 'l' && j != 'r' && j != 'c')
fprintf (stderr, "error: invalid justification '%c' "
"(defaulting to 'left').\n", just);

/* print output in requested justification */
formatted (text, j, width, lines);

/* free all memory allocated in program */
freecdp (text, lines);

return 0;
}

char **inputfile (char ***t, FILE *fp, size_t *sz)
{
if (!t || !sz) { /* validate parameters are not NULL */
fprintf (stderr, "%s() error: invalid parameters.\n", __func__);
return NULL;
}

if (!fp) { /* check that file pointer is valid */
fprintf (stderr, "%s() error: file open failed.\n", __func__);
return NULL;
}

size_t idx = 0; /* declare/initialize function variables */
size_t maxl = MAXL;
char ln[MAXC] = {0};

/* allocate MAXL number of pointers */
*t = xcalloc (MAXL, sizeof **t);

while (fgets (ln, MAXC, fp)) { /* read each line in file */

size_t len = strlen (ln); /* calculate length */

/* remove trailing newline (or carriage return) */
while (len && (ln[len-1] == '\n' || ln[len-1] == '\r'))
ln[--len] = 0;

/* allocate & copy ln saving pointer in t[i], increment i by 1 */
(*t)[idx++] = strdup (ln); /* strdup allocates & copies */

if (idx == maxl) { /* check if you reached limit, realloc if needed */
void *tmp = realloc (*t, maxl * sizeof **t * 2);
if (!tmp) {
fprintf (stderr, "%s() virtual memory exhausted.\n", __func__);
return NULL;

}
*t = tmp; /* set new pointers NULL below (sentinel) */
memset (*t + maxl, 0, maxl * sizeof **t);
maxl *= 2;
}
}
*sz = idx; /* update value at address of sz so it is available in main */

if (fp != stdin) fclose (fp);

return *t;
}

/* format 'n' lines of output of 't' justified as specified in 'just'
(left 'l', right 'r' or centered 'c') within a width 'w'.
NOTE: 'w' must be larger than the longest line in 't'.
*/
void formatted (char **t, char just, size_t w, size_t n)
{
if (!t || !*t) return;
size_t i = 0;
size_t lmax = 0;
size_t len[n];

/* calculate the length of each line, set lmax */
for (i = 0; i < n; i++) {
len[i] = strlen (t[i]);
if (len[i] > lmax) lmax = len[i];
}

/* handle w < lmax reformat or error here */
if (w < lmax) {
fprintf (stderr, "%s() error: invalid width < lmax (%zu).\n",
__func__, lmax);
return;
}

/* left justified output */
if (just == 'l') {
for (i = 0; i < n; i++) {
printf ("%s\n", t[i]);
}
return;
}

/* center or right justified output */
for (i = 0; i < n; i++) {
int spaces = w - len[i];
if (just == 'c')
printf ("%*s%s\n", spaces/2, " ", t[i]);
else if (just == 'r')
printf ("%*s%s\n", spaces, " ", t[i]);
}
}

/* help functions below for calloc, free, and to lower-case */
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n",
__func__);
exit (EXIT_FAILURE);
}

return memptr;
}

void freecdp (char **p, size_t n)
{
if (!p) return;
size_t i;

for (i = 0; i < n; i++)
free (p[i]);
free (p);
}

unsigned chr2lower (unsigned c)
{ return ('A' <= c && c <= 'Z') ? c | 32 : c; }


使用/输出示例

$ ./bin/str_justify l 15 dat/fox_4lines.txt
The quick brown
fox jumps over
a lazy
dog.

$ ./bin/str_justify c 15 dat/fox_4lines.txt
The quick brown
fox jumps over
a lazy
dog.

$ ./bin/str_justify r 15 dat/fox_4lines.txt
The quick brown
fox jumps over
a lazy
dog.

关于c - 根据输入来格式化文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33131934/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com