I am trying to figure out how to read input multiple ways. Input can look like this.
N:{-4,2,1}
E:{1,1,9}
W:{-2,5,3}
S:{7,1}
or like this
E:{9,1,1}N:{1,2,-4}W:{3,5,-2}S:{7,1}
I added into my code checking for word END. Its supposed to be working on EOF but on my windows machine it doesnt work. So input END to signal END of input. So far I managed to get them both working separatly... But I need them to both at the same time.
char *skip_whitespace(char *str)
{
//skip any leading whitespace characters
while (*str == ' ' || *str == '\t')
str++;
return str;
}
void read_tokens(int *north, int *west, int *east, int *south, int *north_size, int *west_size, int *east_size, int *south_size)
{
//buffer for reading in input
char buffer[MAX_TOKENS];
//read in the input line by line
while (fgets(buffer, MAX_TOKENS, stdin) != NULL)
{
//remove the newline character from the end of the line
buffer[strcspn(buffer, "\n")] = 0;
//check for the "END" string to end the input
if (strcmp(buffer, "END") == 0)
break;
//split the line at the curly brace character
char *direction_token = strtok(buffer, "{");
char *tokens = strtok(NULL, "}");
//get the direction
char direction = direction_token[0];
//skip any leading or trailing whitespace characters
tokens = skip_whitespace(tokens);
//split the tokens at each comma
char *token = strtok(tokens, ",");
//determine the direction and store the tokens in the appropriate array
if (direction == 'N')
{
while (token != NULL)
{
//skip any leading or trailing whitespace characters
token = skip_whitespace(token);
//store the token in the array
north[*north_size] = atoi(token);
(*north_size)++;
//find the next token
token = strtok(NULL, ",");
}
}
else if (direction == 'W')
{
while (token != NULL)
{
//skip any leading or trailing whitespace characters
token = skip_whitespace(token);
//store the token in the array
west[*west_size] = atoi(token);
(*west_size)++;
//find the next token
token = strtok(NULL, ",");
}
}
else if (direction == 'E')
{
while (token != NULL)
{
//skip any leading or trailing whitespace characters
token = skip_whitespace(token);
//store the token in the array
east[*east_size] = atoi(token);
(*east_size)++;
//find the next token
token = strtok(NULL, ",");
}
}
else if (direction == 'S')
{
while (token != NULL)
{
//skip any leading or trailing whitespace characters
token = skip_whitespace(token);
//store the token in the array
south[*south_size] = atoi(token);
(*south_size)++;
//find the next token
token = strtok(NULL, ",");
}
}
else
{
//invalid direction = error
printf("Nespravny vstup.\n");
}
}
}
Here is the main function. For anyone intrested here is calling and printing.
int main(void)
{
//field for token values
int north[MAX_TOKENS], west[MAX_TOKENS], east[MAX_TOKENS], south[MAX_TOKENS];
//sizes of token value fields
int north_size = 0, west_size = 0, east_size = 0, south_size = 0;
printf("Input:\n");
//fetch token values from input
read_tokens(north, west, east, south, &north_size, &west_size, &east_size, &south_size);
printf("N: { ");
for (int i = 0; i < north_size; i++)
printf("%d, ", north[i]);
printf("}\n");
printf("W: { ");
for (int i = 0; i < west_size; i++)
printf("%d, ", west[i]);
printf("}\n");
printf("E: { ");
for (int i = 0; i < east_size; i++)
printf("%d, ", east[i]);
printf("}\n");
printf("S: { ");
for (int i = 0; i < south_size; i++)
printf("%d, ", south[i]);
printf("}\n");
}
You have an input format that permits optional whitespace, including newlines, between tokens. Your two examples differ only in that one makes use of that option and the other doesn't. In the most basic terms, then, the solution is to make your parser ignore (all) whitespace between tokens, too. Such a parser handles both forms of input presented, and other variants, too.
I do think, however, that fgets() is more a liability here than a help. Your input is not fundamentally line-oriented, and with fgets() you need to (but do not presently) watch out for and handle cases where a long line is split over two or more reads. I suggest tokenizing the input directly from the stream instead of first reading it into an intermediate buffer.
I know that scanf() gets a lot of hate, but it might serve your purpose pretty well here. It already knows how to skip whitespace, to recognize integers, and to match specific characters. Something along these lines, maybe:
while (1) {
char direction;
char delim;
int result;
// scan first part:
result = scanf(" %c : %c", &direction, &delim);
if (result == EOF) {
// end of file
} else if (result != 2 || !is_valid_direction(direction) || delim != '{') {
// invalid input ...
// ... or maybe (part of) an "END" keyword if you decide to
// go ahead with that
}
// ... handle direction code ...
do {
// scan number
int num;
result = scanf("%d %c", &num, &delim);
if (result != 2 || (delim != ',' && delim != '}')) {
// invalid input ...
// unless empty number lists are allowed: N:{}
}
// store number ...
} while (delim == ',');
}
If you want to avoid scanf(), then you can do basically the same thing by reading one character at a time via getchar() or fgetc(). Or, yes, with fgets() too, provided you exercise sufficient care.
That's schematic, of course, not a full implementation of the needed parser
Related
#include <stdio.h>
#include <string.h>
int main() {
int counter1, counter2;
char line[200] = ""; //store all words that don't need to be deleted
char deleteWord[100]; //word that needs to be deleted
char space;
char word[100];
scanf("%s", deleteWord);
while (1) {
scanf("%s", word);
if (feof(stdin))
break;
// increment counter of total words
++counter1;
if (strcmp(word, deleteWord) == 0) {
// see if the word read in == delete word
// increment counter of deleted words
++counter2;
} else
if (strcmp(word, " ") == 0) { // space is an actual space
strcat(line, word);
strcat(line, " ");
} else
if (strcmp(word, "\n")) { // space a new line \n
strcat(line, word);
strcat(line, "\n");
}
}
printf("--NEW TEXT--\n%s", line);
return 0;
}
In summary, my code is supposed to remove a user input string (one or more words) from another user input string (containing or not containing the word(s)) and produce the output. The code removes the word but it adds a newline per word for each iteration. I believe it is doing this because the expression for the second else if is always true. However, when I properly add the strcmp function for the second else if statement, the code does not produce an output at all (no compiler errors - just missing input). Why is this happening and how do I do a strcmp function for a newline?
Your read the words with scanf("%s", word), which poses these problems:
all white space is ignored, so you cannot test for spaces nor newlines as you try to do in the loop, and you cannot keep track of line breaks.
you should tell scanf() the maximum number of bytes to store into the destination array word, otherwise any word longer than 99 characters will cause a buffer overflow and invoke undefined behavior.
you should test the return value of scanf() instead of callin feof() which might be true after the last word has been successfully read. You should simply write the loop as
while (scanf("%99s", word) == 1) {
// increment counter of total words
++counter1;
...
you do not test if the words fit in the line array either, causing a buffer overflow if the words kept amount to more than 199 characters including separators.
To delete a specific word from a stream, you could read one line at a time and delete the matching words from the line:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main() {
char deleteWord[100]; //word that needs to be deleted
char line[1000]; //store all words that don't need to be deleted
printf("Enter the word to remove: ");
if (scanf("%99s", deleteWord) != 1)
return 1;
// read and discard the rest of the input line
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
size_t len = strlen(deleteWord);
printf("Enter the text: ");
while (fgets(line, sizeof line, stdin)) {
char *p = line;
char *q;
while ((p = strstr(p, deleteWord)) != NULL) {
if ((p == line || isspace((unsigned char)p[-1]))
&& (p[len] == '\0' || isspace((unsigned char)p[len]))) {
/* remove the word */
memmove(p, p + len, strlen(p + len) + 1);
} else {
p += len;
}
}
/* squeeze sequences of spaces as a single space */
for (p = q = line + 1; *p; p++) {
if (*p != ' ' || p[-1] != ' ')
*q++ = *p;
}
*q = '\0';
fputs(line, stdout);
}
return 0;
}
I am trying to parse a string from stdin such as this one { 7 , 3,5 ,11, 8, 16, 4, 9, 2
,8, 4, 2} ( there is a \n between 2 and 8 ).
I have made a function to extract the numbers and trim commas spaces and newlines (accepts char* as an input) but the problem is when I try to get input using scanf I can't get spaces so I used fgets instead but fgets will exit as soon as it sees \n.
Is there a way I can get a string from this ?
int nums[1000], count = 0;
char chr;
while(scanf("%c%d", &chr, &nums[count]) > 0) //there was at least one match
{
if(chr == '}')
break; //we have reached the end
if(chr != ',' && chr != '{')
continue; //skip spaces (} is an exception)
count++;
}
You can use fgets to read the full line and use strtok to read the numbers. The example below will also treat \n as a comma ,
char line[512];
char *buf = 0;
while(fgets(line, sizeof(line), stdin))
{
if(!strstr(line, "{") && !buf)
continue;
if(!buf)
{
buf = strdup(line);
}
else
{
buf = realloc(buf, strlen(buf) + strlen(line) + 1);
strcat(buf, line);
}
if(strstr(line, "}"))
{
char *token = strtok(buf, "{");
strtok(buf, ",}\n");
while(token)
{
int n = 0;
sscanf(token, "%d", &n);
printf("%d, ", n);
token = strtok(NULL, ",}\n");
}
free(buf);
break;
}
}
The task is: to read the text from file and to read an array of delimiters from keyboard. Than the program should search the sequence of delimiters in the text and, if it would be found 3 times or more, swap all the odd strings in a circle. Also it should detete all the words, which exceed the length limit, entered by user, but only in odd strings.
This is what i've got now:
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
int main(void)
{
setlocale(LC_ALL, "Russian"); //entering the text
const int numberOfCharactersToRead = 128;
char* inputText = (char*)(malloc(sizeof(char) * numberOfCharactersToRead));
FILE *fp;
fopen_s(&fp, "D:\texxxt.txt", "r");
if (fp == NULL)
{
printf("nFile not foundn");
system("pause");
return 0;
}
fgets(inputText, numberOfCharactersToRead, fp);
printf("Enter the sequence of delimiters: "); //entering delimiters
const int numberOfDelimitersToRead = 6;
char* delimiters = (char*)(malloc(sizeof(char) * numberOfDelimitersToRead));
int indexer = 0;
for (indexer = 0; indexer < numberOfDelimitersToRead; indexer++)
{
delimiters[indexer] = getchar();
}
//Trying to use strtok in order to devide text into rows (unsuccesful)
char delims[] = "/n";
char *pch = strtok_s(NULL, inputText, &delims);
printf("nLexems:");
while (pch != NULL)
{
printf("n%s", pch);
pch = strtok_s(NULL, inputText, &delims);
}
return 0;
}
int symcount(void)
{ //function searching the quantity of delimiters
char str[20], ch;
int count = 0, i;
printf("nEnter a string : ");
scanf_s("%s", &str);
printf("nEnter the character to be searched : ");
scanf_s("%c", &ch);
for (i = 0; str[i] != ''; i++)
{
if (str[i] == ch)
count++;
}
if (count == 0)
printf("nCharacter '%c'is not present", ch);
else
printf("nOccurence of character '%c' : %d", ch, count);
return (0);
}
I dont really know how to devide the text into rows and how to make my program differentiate even and odd strings. I'm really confused
The definition of strtok_s is the following:
char *strtok_s(char *strToken, const char *strDelimit, char **context);
You are mixing up the parameters. The 1st parameter should be a pointer to the input string and the 2nd parameter should be the delimiter string. Finally after the function is executed the 3rd parameter will be passed a pointer to the string after the position where the delimiter was found, or NULL if no delimiter was found. This pointer can then be passed onto the next strtok_s call to continue the search.
char *pchNext;
char *pch = strtok_s(inputText, delimiters, &pchNext);
while (pch != NULL)
{
printf("\n%s", pch);
pch = strtok_s(NULL, delimiters, &pchNext); // The first parameter can be NULL here
}
Also, the textual representation of the newline character is \n, not /n or n.
I have created the two following functions. The first, eatWrd, returns the first word in a string without any white spaces, and removes the first word from the input string:
MAX is a number representing the max length of a string
char* eatWrd(char * cmd)
{
int i = 0; //i will hold my place in cmd
int count = 0; //count will hold the position of the second word
int fw = 0; //fw will hold the position of the first word
char rest[MAX]; // rest will hold cmd without the first word
char word[MAX]; // word will hold the first word
// start by removing initial white spaces
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
fw++;
}
// now start reading the first word until white spaces or terminating characters
while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
word[i-fw] = cmd[i];
i++;
count++;
}
word[i-fw] = '\0';
// now continue past white spaces after the first word
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
}
// finally save the rest of cmd
while(cmd[i] != '\n' && cmd[i] != '\0'){
rest[i-count] = cmd[i];
i++;
}
rest[i-count] = '\0';
// reset cmd, and copy rest back into it
memset(cmd, 0, MAX);
strcpy(cmd, rest);
// return word as a char *
char *ret = word;
return ret;
}
The second, frstWrd, just returns the first word without modifying the input string:
// this function is very similar to the first without modifying cmd
char* frstWrd(char * cmd)
{
int i = 0;
int fw = 0;
char word[MAX];
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
fw++;
}
while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
word[i-fw] = cmd[i];
i++;
}
word[i-fw] = '\0';
char *ret = word;
return ret;
}
To test the function, I used fgets to read a string from the User(me), and then I printed three strings (frstWrd(input), eatWrd(input), eatWrd(input)). I would have expected that given a string, "my name is tim" for example, the program would print "my my name", but instead it prints the third word three times over, "is is is":
// now simply test the functions
main()
{
char input[MAX];
fgets(input, MAX - 1, stdin);
printf("%s %s %s", frstWrd(input), eatWrd(input), eatWrd(input));
}
I have looked over my functions over and over and cannot see the mistake. I believe there is simply something I don't know about printf, or about using multiple string modification functions as arguments in another function. Any insight would be helpful thanks.
As I see rest and word are local variables in the function eatWrd. So it is bad practice to return pointer to such memory outside functions.
EDIT 1:
Also you should understand, that in line
printf("%s %s %s", frstWrd(input), eatWrd(input), eatWrd(input));
function eatWrd(input) could be called the first (before frstWrd(input)).
EDIT 2:
This can be usefull in finction eatWrd
//char rest[MAX]; // rest will hold cmd without the first word
char * rest = (char*) malloc(MAX);
And new main let be as:
int main()
{
char input[MAX];
fgets(input, MAX - 1, stdin);
printf("%s ", frstWrd(input));
printf("%s ", eatWrd(input));
printf("%s\n", eatWrd(input));
}
And in the end my solution for frstWrd (just to show how standard functions can be useful):
char* frstWrd(char * cmd)
{
char * word = (char *) malloc(MAX);
sscanf(cmd, "%s", word);
return word;
}
I need to make a program that will emulate the terminal of Linux. Since some system calls requires 1,2 or more arguments, I want to make sure that the number of parameters given are correct. I'm using strtok() to separate the call name from the arguments, but I need to know how many tokens strtok() created to compare it.
Here's and example code:
char *comand = (char*) malloc(sizeof(char)*100);
char *token;
char *path1 = (char*) malloc(sizeof(char)*100);
char *path2= (char*) malloc(sizeof(char)*100);
fgets(comand, 100, stdin);
printf( "\nYou entered: %s \n", comand);
token = strtok(comand ," ");
//Check the number of tokens and add a condition in each IF to match
if (strcmp("ls",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("cat",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("cp",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
token = strtok(NULL," ");
strcpy(path2,token);
}
else if (strcmp("mv",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
token = strtok(NULL," ");
strcpy(path2,token);
}
else if (strcmp("find",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("rm",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("mkdir",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("rmdir",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("quit",token) == 0) {
exit(0);
}
else print("Number of parameters do not match);
the only thing strtok() does is look for the next occurance of the delimiter and overwrite that character with a \0 and return the pointer with the offset added. the pointer is kept in a static variable that's why a subsequent call to it with a NULL for the char * will perform it on the last string used from the offset that the last delimiter was found.
this page has a very nice example:
http://en.cppreference.com/w/c/string/byte/strtok
If you only want to count the arguments it would be easier to use strchr(), this function searches for a character and returns a pointer to its location. you could use it like this.
unsigned int i = 0;
char *temp = token;
while ( (temp = strchr(temp, '') != NULL) ) {
++i;
}
this has the added benefit of not modifying your original char array while strtok() does!
I would handle this within the functions you create for each command.
you pass all options to the function and there you parse it. either with strtok() or whatever else you want to use.
This keeps it nice and clean within the sub-routines and you will always know what to expect.
if (strcmp("ls",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token); // I would maybe change the path variable name to args
ret = lscmd(path1);
if (ret == -1) {
// invalid input detected
}
}
then you would have a ls function
int lsdcmd(char *args) {
// parse args for argumants you are looking for, return -1 if it fails
// do whatever you want to do.
}
You can count the arguments using strtok this way:
Example:
const char* delimiter = ",";
char* tokens[MAX_NUM_OF_ARGS];
unsigned int index = 0;
char* temp = strtok(buff,delimiter);
while (temp!=NULL){
if(index<MAX_NUM_OF_ARGS){
tokens[index]=temp;
}
index++;
temp = strtok(NULL,delimiter);
}
Then later you can iterate through the array of pointers (tokens) and compare them...