I am processing a string in which each word is separated by spaces. The < indicates it is a input redirection, and > indicates it is a output redirection.
Ex:
< Hello > World
I want to save the words in different variables (char *in, char *out )
How can I do that? I've looked through the string library and none seems to be able to do the job.
Here's what I have so far concerning this question.
char buff[MAXARGS];
char *str;
char *in;
char *out;
if( strchr(buff, '<') != NULL )
{
str = strchr(buff, '<');
str++;
if( *str == ' ' || *str == '\0' || *str == '\n' || *str == '\t' )
{
fprintf( stdout, "User did not specify file name!\n" );
}
else
in = str; // This will save Hello > World all together. I don't want that.
}
Thanks much.
To get you started, here's how you could do it assuming you are allowed to modify buff, and assuming a simple case (at most one < and at most one >).
First, get the position of the < and >
in = strchr(buff, '<');
out = strchr(buff, '>');
Then you artificially split the string:
if (in) {
*in = 0;
in++;
}
if (out) {
*out = 0;
out++;
}
At this point, buff points to a C-terminated string that has no < or >. in is either null, or points to a string that follows < and contains no >. Same for out.
Then you need to "strip" all these strings (remove whitespace), and check that after that they still contain meaningful data.
You'll need a whole lot more logic to get all the cases right, including rejecting invalid input.
u can use this..
char filename[max_path]
str1 = strchr(buff, '<');
str2 = strchr(buff, '>');
memcpy( filename , str1+1 , str2-str1-1 );
so the path between < and > will be in filename.
and
output = str2 + 1;
supposing your input patter is fixed as < input_name > output_name and you want to be able to extract input_name and output_name respectively.
One solution is to split the str using " <>". Following code will print out Hello , World consecutively. Saving them to in and out is left for you as an exercise :)
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="< Hello > World";
char *in;
char *out;
char *pch;
char *del=" <>";
pch = strtok (str,del);
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, del);
}
return 0;
}
You need to decide where the storage for the two filenames is allocated, and how you will know how much storage is provided.
static void find_filename(const char *str, char *name)
{
char c;
while ((c = *str++) != '\0' && isspace((unsigned char)c))
;
if (c != '\0')
{
*name++ = c;
while ((c = *str++) != '\0' && !isspace((unsigned char)c))
*name++ = c;
}
}
int find_io_redirection(const char *str, char *in, char *out)
{
const char *lt = strchr(str, '<');
const char *gt = strchr(str, '>');
if (lt != 0)
find_filename(lt+1, in);
if (gt != 0)
find_filename(gt+1, out);
return(lt != 0 && gt != 0);
}
This code simply assumes that you provide big enough strings for in and out. If you want to be safer, then you tell the function(s) how big each target string is. You can compress that code. You might decide you want to return the number of redirections. You might decide you should know about double output redirections, or double input redirections. You might decide you should return a bit mask indicating which redirections were present. With a considerably more complex interface, you might be able to indicate which parts of the input line represented the I/O redirection; this would help in the calling function to decide which parts of the line should now be ignored.
You'd use the code above like this:
char buffer[MAXCMDLEN];
char in[MAXFILENAMELEN];
char out[MAXFILENAMELEN];
if (fgets(buffer, sizeof(buffer), stdin) != 0)
{
if (find_io_redirection(buffer, in, out))
...process buffer know that I/O redirection is present...
else
...witter about missing I/O redirection...
}
Related
how can split the word from its meaning
1. mammoth: large
My code:
void ReadFromFile(){
FILE *dictionary = fopen("dictionary.txt", "r");
char word[20];
char meaning[50];
while(fscanf(dictionary, "%[^:]:%[^\t]\t", word, meaning) == 2){
printf("%s %s\n", word, meaning);
}
fclose(dictionary);
Assuming the word and the meaning do not contain digits and dots,
my approach is the following:
First, split the input line on the digits and dots into the tokens which
have the form as word: meaning.
Next separate each token on the colon character.
As a finish up, remove the leading and trailing blank characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INFILE "dictionary.txt"
void split(char *str);
void separate(char *str);
char *trim(char *str);
/*
* split line on serial number into "word" and "meaning" pairs
* WARNING: the array of "str" is modified
*/
void
split(char *str)
{
char *tk; // pointer to each token
char delim[] = "0123456789."; // characters used in the serial number
tk = strtok(str, delim); // get the first token
while (tk != NULL) {
separate(tk); // separate each token
tk = strtok(NULL, delim); // get the next token
}
}
/*
* separate the pair into "word" and "meaning" and print them
*/
void
separate(char *str)
{
char *p;
if (NULL == (p = index(str, ':'))) {
// search a colon character in "str"
fprintf(stderr, "Illegal format: %s\n", str);
exit(1);
}
*p++ = '\0'; // terminate the "word" string
// now "p" points to the start of "meaning"
printf("%s %s\n", trim(str), trim(p));
}
/*
* remove leading and trailing whitespaces
* WARNING: the array of "str" is modified
*/
char *
trim(char *str)
{
char *p;
for (p = str; *p != '\0'; p++); // jump to the end of "str"
for (; p > str && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '\0'); p--);
// rewind the pointer skipping blanks
*++p = '\0'; // chop the trailing blanks off
for (p = str; *p != '\0' && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n'); p++);
// skip leading blanks
return p;
}
int
main()
{
FILE *fp;
char str[BUFSIZ];
if (NULL == (fp = fopen(INFILE, "r"))) {
perror(INFILE);
exit(1);
}
while (NULL != fgets(str, BUFSIZ, fp)) {
split(trim(str));
}
fclose(fp);
return 0;
}
Output:
foe enemy
vast huge
purchase buy
drowsy sleepy
absent missing
prank trick
[snip]
[Alternative]
I suppose C may not be a suitable language for this kind of string manipulations. High-level languages such as python, perl or ruby will solve it with much fewer codes. Here is an example with python which will produce the same results:
import re
with open("dictionary.txt") as f:
s = f.read()
for m in re.finditer(r'\d+\.\s*(.+?):\s*(\S+)', s):
print(m.group(1) + " " + m.group(2))
I am new to C and am getting very frustrated with learning this language. Currently I'm trying to write a program that reads in a program textfile, reads and prints all the string literals, and tokens each on separate line. I have most of it except for one snag. within the text file there is a line such as: (..text..). I need to be able to search, read and print all the text is inside the parentheses on it's own line. Here is an idea I have so far:
#define KEY 32
#define BUFFER_SIZE 500
FILE *fp, *fp2;
int main()
{
char ch, buffer[BUFFER_SIZE], operators[] = "+-*%=", separators[] = "(){}[]<>,";
char *pus;
char source[200 + 1];
int i, j = 0, k = 0;
char *words = NULL, *word = NULL, c;
fp = fopen("main.txt", "r");
fp2 = fopen ("mynewfile.txt","w") ;
while ((ch = fgetc(fp)) != EOF)
{
// pus[k++] = ch;
if( ch == '(')
{
for ( k = 0;, k < 20, K++){
buffer[k] = ch;
buffer[k] = '\0';
}
printf("%s\n", buffer)
}
....
The textfile is this:
#include <stdio.h>
int main(int argc, char **argv)
{
for (int i = 0; i < argc; ++i)
{
printf("argv[%d]: %s\n", i, argv[i]);
}
}
So far I've been able to read char by char and place it into a buffer. But this idea just isn't working, and I'm stumped. I've tried dabbling with strcopy(), ands strtok, but they all take char arrays. Any ideas would be appreciated thank you.
Most likely the best way would be to use fgets() with a file to read in each line as a string (char array) and then delimit that string. See the short example below:
char buffer[BUFFER_SIZE];
int current_line = 0;
//Continually read in lines until nothing is left...
while(fgets(buffer, BUFFER_SIZE - 1, fp) != NULL)
{
//Line from file is now in buffer. We can delimit it.
char copy[BUFFER_SIZE];
//Copy as strtok will overwrite a string.
strcpy(copy, buffer);
printf("Line: %d - %s", current_line, buffer); //Print the line.
char * found = strtok(copy, separators); //Will delmit based on the separators.
while(found != NULL)
{
printf("%s", found);
found = strtok(NULL, separators);
}
current_line++;
}
strtok will return a char pointer to where the first occurrence of a delimiter is. It will replace the delimiter with the null terminator, thereby making "new" string. We can pass NULL to strtok to tell it to continue where it left off. Using this, we can parse line by line from a file based on multiple delimiters. You could save these individual string or evaluate them further.
I'm making a program which reads from stdin or from a file and counts number of if statements. I've done it but if for example I have a variable called "asdifasd" or "ifasd" it shall be counted as an if statement. How do I extract solely the if-statements? Here's my code:
char str[150];
int ifs = 0;
while (fgets(str, sizeof(str), stdin) != NULL)
{
char *p = str;
while (((p = (strstr(p, "if"))) != NULL)) {
ifs++;
++p;
}
}
I've been thinking about doing something with strncmp but I'm not sure how.
After you've found "if" using strstr, check the characters immediately before and after to make sure they're not a letter. Like:
{
char *p = str;
while (((p = (strstr(p, "if"))) != NULL)) {
if ((p == str || !isalnum((unsigned char) p[-1])) &&
!isalnum((unsigned char) p[2]))
++ifs;
++p;
}
}
Currently I am working on a program that allows a user to enter a string that is then tokenized, then the tokens are printed to the screen by using an array of pointers. It is "supposed" to do this by calling my tokenize function which reads the input string until the first separator ( ' ', ',', '.', '?', '!'). It then changes that separator in my string to a NULL char. It then should return a pointer to the next character in my string.
In main after the string has been input, it should keep calling the tokenize function which returns pointers which are then stored in a array of pointers to later print my tokens. Once the tokenize() returns a pointer to a NULL character which is at the end of my string it breaks from that loop. Then I print the tokens out using my array of pointers.
//trying to be detailed
#include <stdio.h>
#include <string.h>
char *tokenize ( char *text, const char *separators );
int main ( void )
{
char text[30];
char separators[6] = { ' ','.',',','?','!','\0'};
char *pch = NULL;
int tokens[15];
int i = 0;
int j = 0;
printf("Enter a string: \n");
fgets( text, 30, stdin );
printf("%s", text );
pch = tokenize ( text, separators );
do
{
pch = tokenize ( pch, separators );
//printf("%c", *pch);
tokens[i] = pch;
i++;
}
while( *pch != NULL );
i--;
while( j != i )
{
printf("%s", tokens[i] );
j++;
}
return 0;
}
char *tokenize ( char *text, const char *separators )
{
while( text != NULL )
{
if( text != NULL )
{
while( separators != NULL )
{
if( text == separators )
{
text = '\0';
}
separators++;
}
}
text++;
}
return text;
}
3 big known problems currently.
1.When I compile, it reads the string then prints it, then gets stuck in a endless loop with nothing printing, still trying to get input.
2. Im pretty sure I am using the " * " for my pointers in the wrong place.
3. My function passes in a reference to my arrays, so I assumed i could just increment them as is.
I appreciate any feedback! I will be watching this post constantly. If i left something unclear, I can respecify. Thanks.
You had right idea for approaching the problem, but you had numerous pointer/int errors throughout your code. Make sure you compile your code with Warnings enabled, this will tell you where you have problems in your code. (don't expect your code to run correctly until you address and eliminate all warnings). At a minimum, compile with -Wall -Wextra options in your build command.
There are a lot easier ways to do this, but for the learning experience, this is a great exercise. Below is your code with the errors corrected. Where possible, I have left your original code commented so you can see where the issues were. I also include a bit of code to remove the newline included by fgets at the end of text. While this isn't required, it is good practice not to have stray newlines filter through your code.
Let me know if you have questions:
#include <stdio.h>
#include <string.h>
char *tokenize ( char *text, const char *separators );
int main ( void )
{
char text[30];
char separators[6] = { ' ','.',',','?','!','\0'};
char *pch = NULL;
char *tokens[15] = {0}; /* declare array of pointers */
int i = 0;
int j = 0;
printf("Enter a string: \n");
fgets( text, 30, stdin );
size_t len = strlen (text);
if (text[len-1] == '\n') /* strip newline from text */
text[--len] = 0;
pch = text; /* pch pointer to next string */
char *str = text; /* str pointer to current */
do
{
pch = tokenize ( str, separators ); /* pch points to next */
tokens[i++] = str; /* save ptr to token */
str = pch; /* new start of str */
}
while (pch != NULL && *pch != 0); /* test both pch & *pch */
printf ("\nTokens collected:\n\n");
while (tokens[j]) /* print each token */
{
printf(" token[%d]: %s\n", j, tokens[j] );
j++;
}
printf ("\n");
return 0;
}
char *tokenize ( char *text, const char *separators )
{
const char *s = separators; /* must use pointer to allow reset */
//while( text != NULL )
while( *text != '\0' )
{
s = separators; /* reset s */
while( *s != 0 ) /* 0 is the same as '\0' */
{
//if( text == separators )
if( *text == *s )
{
//text = '\0';
*text = '\0';
return ++text;
}
s++;
}
text++;
}
return text;
}
Example output:
$ ./bin/tokenizestr
Enter a string:
This is a test string
Tokens collected:
token[0]: This
token[1]: is
token[2]: a
token[3]: test
token[4]: string
Maybe you will want to take a look at
strsep and this post Split string with delimiters in C
If you need more reference points try searching "split string" it is what you want to do if I understood correctly.
I need a program to reverse the order of all strings stored in one or more text files. This is what i've got so far:
#include <stdio.h>
main(int argc, char *argv[])
{
int i;
for (i=1;i < argc;i++)
{
FILE *MyFile=fopen(argv[i], "r");
int i,len;
char str[1000], *ptr;
fgets(str, 1000, MyFile);
ptr = str;
for(i=0;i<1000;i++)
{
if(*ptr == '\0') break;
ptr++;
}
len = i;
ptr--;
for(i=len; i>0; i--)
{
printf("%c",*ptr--);
}
printf("\n");
fclose (MyFile);
}
return 0;
}
What i'm not being able to do is to loop the program correctly so that it reverses all strings. Currently it reverses the first string of all files, but when it encounters a line break the fgets stops. What i've tried to do is to count the lines in the current file, do a for loop, and at the end do another fgets(str, 1000, MyFile); to advance the fgets, but I somehow manage to mess things up.
Another option I thought of is to create a separate function which only reverses a given string, and inside the main function call that function the appropriate number of times, but i'm not sure how to handle the argc and *argv[] in this situation.
Any help? Thanks!
You are clobbering the i variable for the outer loop with another one declared inside. This is most probably why it doesn't work.
You should use strlen() function to get the string length instead of calculating it manually.
Unless you are guaranteed to have strings of at most 1000 bytes, you should consider using a smarter algorithm to cater for longer strings.
Accumulate each char in a buffer until end-of-string (\0) detected. Then print it in reverse.
printf_reverse(const char *buf, size_t len) {
while (len > 0) {
fputc(buf[--len], stdout);
}
}
char buf[1000];
size_t len = 0;
int ch;
while ((ch == fgetc(MyFile)) != EOF) {
if (ch == '\0') {
printf_reverse(buf, len);
len = 0;
}
// You may want not use EOL as part of the reverse
else if (ch == '\n') {
printf_reverse(buf, len);
fputc(ch, stdout);
len = 0;
}
else if (len < sizeof(buf)) {
buf[len++] = ch;
}
else {
; // handle error string too long
}
printf_reverse(buf, len);
OP says "ABCD 1234 Should output: DCBA 4321". In C, a string ends with a \0. It is not clear if the source file has embedded \0 or OP also wants to use a space to indicate the end of the string.