Da Sie beide underlength und overlength Linien zuverlässig erfassen müssen, und neu synchronisieren Sie Eingabe nach entweder, es ist wahrscheinlich am einfachsten, eine Funktion zu schreiben, die getc()
die Daten lesen verwendet.
Ihre Standard-Funktionsoptionen:
fgets()
— wird nicht zu viel lesen, aber man müßte, um zu bestimmen, ob es eine neue Zeile bekam (die in der Eingabe enthalten sein würden) und befaßt sich mit Resynchronisation beim Lesen einer überlangen Linie (nicht sehr schwierig).
fread()
— wird genau die richtige Länge lesen, und wäre eine gute Wahl, wenn Sie denken, dass Überlängen und Unterlängen werden verschwindend selten vorkommen. Resynchronisation nach einem Fehler ist alles andere als trivial, besonders wenn Sie angrenzende fehlerhafte Zeilen erhalten.
getline()
— von POSIX 2008. Erteilt genügend Speicher für die Länge der Zeile, die es liest, was eine kleine Verschwendung ist, wenn Sie einfach überlange Zeilen verwerfen.
Da sie nicht geeignet sind, schreiben Sie am Ende Ihre eigenen.
Jetzt getesteter Code. (Das Update wurde in der ersten if
wie von Dave diagnostiziert benötigt. Das Problem war, dass ich ursprünglich den inversen Zustand schrieb (if ((c = getc(fp)) != EOF && c != '\n')
), dann abgelenkt wurde, nachdem ich die Logik invertiert, was zu einer 'unvollständigen Inversion' der Bedingung.)
Die wichtigsten Teile davon sind die zwei while-Schleifen.
Die erste While-Schleife liest bis zum Ende der Zeile, speichert die Daten und zählt die Zeichen — den normalen Betrieb. Wenn die Linie die richtige Länge hat, wird die Schleife unterbrochen, wenn die neue Zeile gelesen wird. Beachten Sie den <=
Zustand; Wenn Sie die Schleife betrachten, wenn linelen == 1
, werden Sie sehen, dass <=
hier korrekt ist, obwohl <
ist üblich. Wenn die Leitung kurz ist, zeigt count
dies an.
Die zweite while-Schleife behandelt überlange Zeilen, liest bis zum Ende der Zeile und verwirft die Ergebnisse. Es verwendet x
anstelle von c
, weil in der Return-Anweisung c
benötigt wird.
/*
@(#)File: $RCSfile: rdfixlen.c,v $
@(#)Version: $Revision: 1.2 $
@(#)Last changed: $Date: 2012/04/01 00:15:43 $
@(#)Purpose: Read fixed-length line
@(#)Author: J Leffler
*/
/* Inspired by https://stackoverflow.com/questions/9957006 */
#include <stdio.h>
#include <assert.h>
extern int read_fixed_length_line(FILE *fp, char *buffer, int linelen);
/* Read line of fixed length linelen characters followed by newline. */
/* Buffer must have room for trailing NUL (newline is not included). */
/* Returns length of line that was read (excluding newline), or EOF. */
int read_fixed_length_line(FILE *fp, char *buffer, int linelen)
{
int count = 0;
int c;
assert(fp != 0 && buffer != 0 && linelen > 0);
while (count < linelen)
{
if ((c = getc(fp)) == EOF || c == '\n')
break;
buffer[count++] = c;
}
buffer[count] = '\0';
if (c != EOF && c != '\n')
{
/* Gobble overlength characters on line */
int x;
while ((x = getc(fp)) != EOF && x != '\n')
count++;
}
return((c == EOF) ? EOF : count);
}
#ifdef TEST
#include "posixver.h"
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
enum { MAXLINELEN = 10 };
int actlen;
char line[16];
int lineno = 0;
memset(line, sizeof(line), '\0');
while ((actlen = read_fixed_length_line(stdin, line, MAXLINELEN)) != EOF)
{
lineno++;
if (actlen != MAXLINELEN)
{
if (actlen > MAXLINELEN)
printf("%2d:L: length %2d <<%s>>\n", lineno, actlen, line);
else
printf("%2d:S: length %2d <<%s>>\n", lineno, actlen, line);
}
else
printf("%2d:R: length %2d <<%s>>\n", lineno, actlen, line);
assert(line[MAXLINELEN-0] == '\0');
assert(line[MAXLINELEN+1] == '\0');
}
return 0;
}
#endif /* TEST */
Testdaten und Ausgangs
$ cat xxx
abcdefghij
a
Abcdefghij
ab
aBcdefghij
abc
abCdefghij
abcd
abcDefghij
abcde
abcdEfghij
abcdef
abcdeFghij
abcdefg
abcdefGhij
abcdefgh
abcdefgHij
abcdefghi
abcdefghIj
abcdefghiJ
abcdefghiJ1
AbcdefghiJ
abcdefghiJ12
aBcdefghiJ
abcdefghiJ123
$ ./rdfixlen < xxx
1:S: length 0 <<>>
2:R: length 10 <<abcdefghij>>
3:S: length 1 <<a>>
4:R: length 10 <<Abcdefghij>>
5:S: length 2 <<ab>>
6:R: length 10 <<aBcdefghij>>
7:S: length 3 <<abc>>
8:R: length 10 <<abCdefghij>>
9:S: length 4 <<abcd>>
10:R: length 10 <<abcDefghij>>
11:S: length 5 <<abcde>>
12:R: length 10 <<abcdEfghij>>
13:S: length 6 <<abcdef>>
14:R: length 10 <<abcdeFghij>>
15:S: length 7 <<abcdefg>>
16:R: length 10 <<abcdefGhij>>
17:S: length 8 <<abcdefgh>>
18:R: length 10 <<abcdefgHij>>
19:S: length 9 <<abcdefghi>>
20:R: length 10 <<abcdefghIj>>
21:R: length 10 <<abcdefghiJ>>
22:L: length 11 <<abcdefghiJ>>
23:R: length 10 <<AbcdefghiJ>>
24:L: length 12 <<abcdefghiJ>>
25:R: length 10 <<aBcdefghiJ>>
26:L: length 13 <<abcdefghiJ>>
$
@gbulmer 'fgets' tut ** NICHT ** den Zeilenumbruch verwerfen. – Dave
@Dave - Danke, dass Sie das entdeckt haben. Sehr verwirrend :-(Ich denke, ich dachte, dass gets() (das ist noch schwieriger zu verwenden, weil es keine Pufferlänge dauert). Ich lösche, um Verwirrung zu vermeiden. – gbulmer
@ JonathanLeffler 'c == EOF && c! = ' \ n''? Der zweite Teil versagt nie .. – Dave