Scanf with optional text - c

I'm trying to read a .txt file, which contains a name and a last name in the first line and below contains an array
The problem is that the first line may or may not one letter A in brackets like this: [A].
for instance:
Jose Perez [A] or may have jose perez
When I run here mentioned code, if the first line does not contain a [A] performs a shift of values, for example the value of the matrix [1] [1] is up as tester and insert a 0 at the end to complete the matrix.
Here is a sample of what gives the code when there is a [A] in the first line and when not
FILE* text=NULL;
text=fopen(archivo,"r");
char name[100];
char last_name [100];
char verifier [10];
int matriz[6][4];
int i ;
int lu,ma,mi,ju,vi;
if (text == NULL) {
}
else {
fscanf(text,"%s %s %s [^\n]",name, last_name, verifier);
for( i= 0; i<7;i++){
fscanf(text,"%d %d %d %d %d [^\n]",&lu, &ma, &mi,&ju,&vi);
matriz[i][0] = lu;
matriz[i][1] = ma;
matriz[i][2] = mi;
matriz[i][3] = ju;
matriz[i][4] = vi;
}
Result:
Jose Perez 1
0 0 0 0 0
1 0 1 0 1
0 1 1 1 1
0 1 1 0 0
1 0 0 0 0
1 1 1 0 0
1 0 1 0 0
Juan Perez A
1 0 1 1 1
0 0 1 1 1
0 0 1 0 1
0 0 1 1 1
1 0 1 0 1
0 0 1 1 1
0 1 1 1 0
As could be solved?

char line[80], fname[16], lname[16], third[4];
fgets(line, 80, fp)
if (sscanf(line, "%s %s %s\n",
fname, lname, third) == 3 && strcmp(third, "[A]") == 0)
// the line has a [A] at the end
else if (sscanf(line, "%s %s\n", fname, lname) == 2)
// the line does not have a [A] at the end
else
fprintf(stderr, "Invalid line");
fgets reads the next line from the file. If it is not null, we check the return value of sscanf. It returns the number of items parsed. So, on success it should return 3. If it contains a [A] at the end of the line, the third variable should compare equal to [A].
After all this, we can proceed to read the array.

Since your verifier is always a single character, you can let scanf do the work. In the example below it will stop scanning if the opening bracket does not exist, but get the verifier character otherwise:
char name[100];
char last_name [100];
char verifier = 0;
int n = fscanf("%s %s [%c]", name, last_name, &verifier);
If n == 2 there was no verifier, if n == 3 there was a verifier, and in any other case, there was an error.

Related

How to read a file, convert letters, and print string and integers to an array in c?

struct reviewStruct {
char reviewer[50];
int feedback[3];
};
int readReviews(FILE *file, struct reviewStruct reviews[10]) {
int i;
file = fopen("Names.txt", "r");
if(file == NULL) {
printf("Error");
exit(-1);
}
for(i = 0; i < 10; i++) {
fgets(reviews[i].reviewer, 50, file);
}
fclose(file);
for(i = 0; i < 10; i++) {
printf("%s", reviews[i].reviewer);
}
return 0;
}
Hello, I'm trying to read a file line by line and print it to an array, with a catch. Whenever a 'Y' or 'y' appears, it converts that letter into a 1, and if an 'N' or 'n' appears, it is converted into a 0 (zero), excluding the first word of every line. For example, I have a file with the following information:
charlie Y n N
priya N n Y
lance y y Y
stan N y n
arin N n N
This is the text file called Names.txt, I want to save the integer information to the array called "feedback", so that it looks like this when printed using a for loop:
1 0 0
0 0 1
1 1 1
0 1 0
0 0 0
How do I populate the feedback array such that it can be printed along with the names using a for loop as it is in the following image?
charlie 1 0 0
priya 0 0 1
lance 1 1 1
stan 0 1 0
arin 0 0 0
Thanks.

How to get the third column of text file in C programming

I have a text file that contains:
1 1 1
1 2 2
1 3 2
1 7 5
1 8 4
1 9 4
1 10 2
...
and this is my function:
void addRatings()
{
int n,m,l;
int a[50][100];
MovieR = fopen("d://ratings.txt","r");
l = LineNum(MovieR);
MovieR = fopen("d://ratings.txt","r");
for(int i=0;i<l;i++)
{
fscanf(MovieR,"%[^\t]\t%[^\t]\t%[^\t]\n",&n,&m,&a[n][m]);
}
}
Now I want to get the first and second column for n and m
then I want to give third column to the a[n][m].
How can I do that?
You need to read the third value into a temporary variable, and then store that value into the array if and only if the following conditions are met:
fscanf returned 3, meaning that it actually found three numbers
the value for n is between 0 and 49 inclusive
the value for m is between 0 and 99 inclusive
And the code doesn't need to count the number of lines (using LineNum()). The loop should end when fscanf runs out of numbers to read, i.e. returns something other than 3.
The resulting code looks something like this:
void addRatings(void)
{
int a[50][100] = {{0}}; // initialize all ratings to 0
FILE *MovieR = fopen("d://ratings.txt", "r");
if (MovieR != NULL)
{
int n, m, rating;
while (fscanf(MovieR, "%d%d%d", &n, &m, &rating) == 3) // loop until end-of-file
{
if (n < 0 || n > 49 || m < 0 || m > 99) // check for valid indexes
break;
a[n][m] = rating;
}
fclose(MovieR);
}
}

Updating a matrix with special cases

I am trying to write a function which gets a matrix 9x9 and updates it accordingly to user's input with the following rules:
Valid number is between 1 and 9 (zero is invalid).
I have to use scanf until I get EOF.
Input has digits and symbols. valid input is a pair of two digits following with a symbol or EOF or space. string with more than two digits is invalid. for example (123% isn't valid but 12% is valid).
Example:
Input: 10 33%55^21 $123%
Output:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Explanation: 10 and 123 are invalid. 33, 55 and 21 are valid so we will put 1 in 22, 44 and 10.
What I tried to do:
void updateMarix(int matrix[][9]) {
int digits = 0, one_previous, two_previous;
char input;
while (scanf("%c", &input) != EOF) {
if(isValidDigit(input)) {
digits++;
if(digits == 1) {
two_previous = input - '0' - 1;
continue;
} else if(digits == 2){
one_previous = input - '0' -1;
continue;
}
} else if(digits == 2) {
matrix[two_previous][one_previous]++;
}
digits = 0; // reset
}
}
most tests are end with success, but some of them are fail. I think that is because I don't handle with the last input (if for example it ends with 22 it won't update it because with my implementation, the update is in the next iteration when other symbol got as input).
Is there a better implementation for this? My code became messy and not clean.
*Edit: It should ignore invalid input and a3b doesn't counts, a03b also doesn't counts but a13b does counts as 13 meaning we should increase the number in matrix[0][2].
Edit 2: #JonathanLeffler menationed FSM so I tried to create one:
Although it doesn't handles the case of 1234 (invalid number) or 123 (also invalid). The most similar thing was to create an arrow from second number to symbol (but it isn't quite true because in 1234%12 only 12 is valid.
I think your FSM needs 4 states plus the end state:
Zero digits read (D0).
One digit read (D1).
Two digits read (D2).
Digits are invalid but no more error reporting needed (DI).
There are 4 different inputs, too:
Digit 1-9.
Digit 0.
Other.
EOF.
I've used a switch on state and if/else code in each state, but it leads to somewhat verbose code. OTOH, I believe it handles inputs correctly.
/*
** FSM
** States: 0 digits (D0), 1 digit (D1), 2 digits (D2), digits invalid (DI)
** Inputs: digit 1-9 (D), digit 0 (0), other (O), EOF.
** Action: S - save, E - error, I - ignore, P - print
** Body of FSM encodes "action;state"
**
** State D0 D1 D2 DI
** Input
** D S;D1 S;D2 E;D2 I;DI
** O I;D0 E;D0 P;D0 I;D0
** 0 E;D2 E;D2 E;D2 I;DI
** EOF I;end E;end P;end I;end
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
enum State { D0, D1, D2, DI };
enum Input { Digit, Zero, Other, End };
static int debug = 0;
static enum Input input(int *rv)
{
int c = getchar();
if (debug)
printf("Input: %c\n", (c == EOF) ? 'X' : c);
*rv = c;
if (c == EOF)
return End;
if (isdigit(c))
{
*rv = c - '0';
return (c == '0') ? Zero : Digit;
}
return Other;
}
static void updateMatrix(int matrix[9][9])
{
char pair[2] = { 0, 0 };
enum State state = D0;
int c;
enum Input value;
while ((value = input(&c)) != End)
{
switch (state)
{
case D0:
if (value == Digit)
{
pair[0] = c;
state = D1;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
}
break;
case D1:
if (value == Digit)
{
pair[1] = c;
state = D2;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
fprintf(stderr, "Received one digit where two expected\n");
state = D0;
}
break;
case D2:
if (value == Digit)
{
fprintf(stderr, "Received more than two digits where two were expected\n");
state = DI;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
state = D0;
}
break;
case DI:
if (value == Other)
state = D0;
break;
}
}
if (state == D2)
{
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
}
else if (state == D1)
fprintf(stderr, "Received one digit where two expected\n");
}
static void dump_matrix(const char *tag, int matrix[9][9])
{
printf("%s:\n", tag);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
printf("%4d", matrix[i][j]);
putchar('\n');
}
}
int main(void)
{
int matrix[9][9] = { 0 };
updateMatrix(matrix);
dump_matrix("After input", matrix);
return 0;
}
On your test input, it produces the output:
Received zero digit - invalid
Valid number 33
Valid number 55
Valid number 21
Received more than two digits where two were expected
After input:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
On the mostly-invalid input file:
123345132
bbbb12cccc1dddd011dd
it produces the output:
Received more than two digits where two were expected
Valid number 12
Received one digit where two expected
Received zero digit - invalid
After input:
0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
You can argue (easily) that the error messages could be more informative (identifying the erroneous character, and possibly the prior valid digits), but it only produces one error message for each invalid sequence, which is beneficial.
You could use a combination of fgets(), sscanf() and strpbrk() for this.
The input line is read into a character array str and a pointer ptr pointing to the part of the string in str being processed is maintained.
First, set up a loop to read input line by line. fgets() will return NULL on EOF.
for(; fgets(str, sizeof(str), stdin); )
{
...
...
...
}
fgets() will read in the trailing newline as well. You could remove it like
str[strlen(str)-1]='\0';
Now inside the above loop, use another loop to process the input line in str like
for(ptr=str; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
//accepted
printf("\n%d", n);
arr[n/10][n%10]=1;
}
//else discarded
}
strpbrk()'s prototype is
char *strpbrk(const char *s1, const char *s2);
and it returns a pointer to the first character in s1 which is a character in the string s2. If there is no match, NULL is returned.
So we are looking to see the first digit part in str that remains to be processed with strpbrk(ptr, "0123456789").
This number part is read into n via sscanf(). If this number is in the range you need, you may accept it.
The %n format specifier is used to find out the number of characters which has been scanned with the sscanf() inorder to find the value by which ptr must be updated. See this post.
The digit in the ones place will be n%10 and that in the tens place will be n/10 as the number you need is a 2-digit number.
You may set your array representing the matrix like
arr[n/10][n%10]=1;
So the whole thing could look something like
char *ptr, str[50];
for(; fgets(str, sizeof(str), stdin); )
{
for(ptr=str, str[strlen(str)-1]=0; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
printf("\n%d", n);
arr[n/10][n%10]=1;
}
}
}
And for your input 10 33%55^21 $123%, the output would be
33
55
21
as 10 and 123 will be discarded.

Generate Binary Sequence

I want to generate permutations of string of 5 0s followed by the permutations of 4 0s and a single 1, followed by the permutations of 3 0s with 2 1s etc? My code is as follows:
#include<stdio.h>
int main(){
int i,j,k,l,s[5];
for(i=0;i<5;i++)
s[i]=0;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(j=0;j<5;j++)
if(i==j)
s[j]=1;
else
s[j]=0;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
}
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(k=0;k<5;k++)
s[k]=0;
s[i]=1;
for(j=i+1;j<5;j++){
s[j]=1;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
for(k=j;k<5;k++)
s[k]=0;
}
}
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
for(k=0;k<5;k++)
s[k]=0;
s[i]=1;
s[j]=1;
for(l=j+1;l<5;l++){
s[l]=1;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
for(k=l;k<5;k++)
s[k]=0;
}
}
}
}
So output is
0 0 0 0 0
---------------------------------------------
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
---------------------------------------------
1 1 0 0 0
1 0 1 0 0
1 0 0 1 0
1 0 0 0 1
0 1 1 0 0
0 1 0 1 0
0 1 0 0 1
0 0 1 1 0
0 0 1 0 1
0 0 0 1 1
---------------------------------------------
1 1 1 0 0
1 1 0 1 0
1 1 0 0 1
1 0 1 1 0
1 0 1 0 1
1 0 0 1 1
0 1 1 1 0
0 1 1 0 1
0 1 0 1 1
0 0 1 1 1
Output is ok. However in my code I use
different for loops for different cases.
Is it possible to use better approach so
that length of the code is reduced?
One approach follows. This solution needs O(n) space and each output string requires O(n) time.
#include <stdio.h>
#include <stdlib.h>
char *buf;
// Print combinations of m 1's in a field of n 0/1's starting at s.
void print_combinations(char *s, int n, int m)
{
// If there is nothing left to append, we are done. Print the buffer.
if (m == 0 && n == 0) {
*s = '\0';
printf("%s\n", buf);
return;
}
// Cut if there are more 1's than positions left or negative numbers.
if (m > n || m < 0 || n < 0) return;
// Append a 0 and recur to print the rest.
*s = '0';
print_combinations(s + 1, n - 1, m);
// Now do the same with 1.
*s = '1';
print_combinations(s + 1, n - 1, m - 1);
}
int main(void)
{
int n = 5;
buf = malloc(n + 1);
for (int m = 0; m <= n; m++) {
print_combinations(buf, n, m);
printf("-----\n");
}
return 0;
}
You could use a recursive function like so - you don't have to print the result when finished, you could add it to a list etc.
The function works by starting with an empty string. At each step you add one more character - in this case you add either a 0 or a 1.
If a 1 is added we account for this by decrementing the ones value on the next call to the function. (In a more general case you could pass a list of all the elements to be permuted - then the process would be to pick from this list, add it to your permutation and remove it from the list. You repeat that until the list is empty and you have permuted all of the elements in the list.)
When the string reaches the desired length we have finished and so we return.
#include <stdio.h>
void recurse(char *str, int length, int maxLength, int ones)
{
if (length == maxLength)
{
// we are finished
printf("%s\n", str);
return;
}
if (ones > 0)
{
// put a 1 into the new string
str[length] = '1';
recurse(str, length + 1, maxLength, ones - 1);
}
if (ones < maxLength - length)
{
// there are still spaces for 0s
// put a 0 into the string
str[length] = '0';
recurse(str, length + 1, maxLength, ones);
}
}
int main()
{
const int maxLength = 5;
char buffer[maxLength + 1];
buffer[maxLength] = 0;
int ones;
for (ones = 0; ones <= maxLength; ones++)
{
printf("Ones: %i\n", ones);
recurse(buffer, 0, maxLength, ones);
printf("\n");
}
return 0;
}
The output looks like this:
Ones: 0
00000
Ones: 1
10000
01000
00100
00010
00001
Ones: 2
11000
10100
10010
10001
01100
01010
01001
00110
00101
00011
Ones: 3
11100
11010
11001
10110
10101
10011
01110
01101
01011
00111
Ones: 4
11110
11101
11011
10111
01111
Ones: 5
11111
Finally, unless you really want to/need to learn/use C, I would recommend using C++ because you get really nice features like std::vector and std::set and so many other things which will make your life so much easier. I would have written this completely different in C++.

Extra edge in my list?

I'm writing code to create a matrix out of a list of edges.
However, when I run said code, I get a "phantom edge" that is not in the input data, which goes on to screw up the rest of my program. The edge is 9,2 in the matrix, or 8,1 in elemental code form.
All elements in the matrix are initialized to 0 before hand.
Here is the input data to do with the matrix:
1 2
1 8
2 8
3 5
3 1
4 5
4 6
5 2
5 9
6 4
6 8
7 4
7 10
8 4
8 6
9 4
9 5
10 7
10 3
Here are the functions that handle the input:
void displayMatrix(int **matrix, int numberVertices){ //function displays the matrix
int i, j;
for(i=0; i<numberVertices; i++) //go through eveyr element
{
for(j=0; j<numberVertices; j++)
{
printf("%d ", matrix[i][j]); //print element
}
printf("\n");
}
printf("\n\n");
}
void inputMatrix(FILE *fp, int ** matrix) //file places value 1 into matrix if edge exists for the adjacency matrix
{
int e1, e2;
while(!feof(fp)) //continue to the end of the file
{
fscanf(fp, "%d %d", &e1, &e2); //get pairs
e1 = e1 - 1; //adjust the edges for array use
e2 = e2 - 1;
matrix[e1][e2] = 1; //place value 1 into appropriate location in adjacency matrix
}
fclose(fp); //close the file connection
}
0 1 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0 0
1 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 1
0 0 0 1 0 1 0 0 0 0
0 *1 0 1 1 0 0 0 0 0
0 0 1 0 0 0 1 0 0 0
*the entry that should not exist, not in the input data
The problem is that you're looping one more additional time than necessary, causing fscanf to fail before the first conversion and thus leaving e1 and e2 as they were from the prior read. As it turns out, the last entry has e1 set to 10 and e2 to 3, so e1 becomes 9 and e2 becomes 2, thus causing your phantom edge.
The cause of this additional loop is because your loop condition doesn't do what you think it does. feof checks if the end-of-file flag has been set, and this can only be set when attempting to read at the end of the file. Since you're checking for end-of-file before your read, you're not actually picking up on this until the next iteration, thus you loop an additional time. The proper correction is very simple; just continue until fscanf results in EOF.
while (fscanf(fp, "%d %d", &e1, &e2) != EOF)
{
matrix[e1 - 1][e2 - 1] = 1;
}
As pointed out in the comments, you're not testing for errors in fscanf.
In particular, you have not yet reached the end of file after reading 10 3, presumably because a newline was encountered.
However, in the next time around fscanf will return zero. Then you subtract 1 from those values (which were not read) to get 9 2.
You can make sure that two integers were read by doing this:
if( 2 != fscanf(fp, "%d %d", &e1, &e2) ) break;
You can try this:
fscanf(fp, "%d %d\n", &e1, &e2);
When you finish the last two digit, there is one more \n,the loop have to continue,this will make trouble

Resources