How to extract contents between a specific character in a c string? - c

Say I have char ch[] = "/user/dir1/file.txt";
I want to use a loop such that:
1st iteration:
prints: "user"
2nd iteration:
prints: "dir1"
3rd iteration:
prints: "file1.txt"
reach the end of string. Exists the loop

You have to use strtok or its threadsafe version if you are developing a multithreaded program:
#include<stdio.h>
#include <string.h>
int main() {
char ch[] = "/user/dir1/file.txt";
// Extract the first token
char * token = strtok(ch, "/");
// loop through the string to extract all other tokens
while( token != NULL ) {
printf( "%s\n", token ); //printing each token
token = strtok(NULL, " ");
}
return 0;
}

A "simple", portable, thread-safe solution that does not modify the string, as the approach using strtok() does. So the approach below can be applied to literals as well!
#include <stdio.h>
#include <string.h>
int main(void)
{
const char * s = "/user/dir1/file.txt";
for (const char * ps = s, *pe;
pe = strchr(ps, '/'), ps != pe ?printf("%.*s\n", (int) (pe - ps), ps) :0, pe;
ps = pe + 1);
}
The only limitation this code is facing, is that the tokens within the string to be parsed may not be longer then INT_MAX characters.

Related

Spilting strings in C with mulitple delimiters [duplicate]

This question already has answers here:
split char string with multi-character delimiter in C
(5 answers)
Closed 1 year ago.
so i need to split the string given with:
const char *inputs[] = {"111adbhsd111gfhds","goal!","zhd!111oosd","111let111"};
to ouput:
char *outputs[]={"adbhsd","gfhds","goal!","zhd!","oosd","let"}
where the delimiter is : "111" .
I tried with strtok , but as the delimiter is of mulitple character , it did't work!
any idea, how it might give the output, will help!
what i have did till now:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t split(
char **outputs, // outputs
const char *separator, // the delimiter
const char **inputs,
size_t num_inputs // no. of input strings, given in input array
){
size_t num_outputs = 0;
int l= 0;
for(size_t i = 0; i < num_inputs ; i++){
if(strstr(*(inputs+i), separator) != NULL){ // to check, if the string of the given input array has the delimiter
char* pos = strstr( *(inputs+i), separator);
//having problem in this part
}
else
{
strcpy( outputs[l] , *(inputs+i));;
l++;
num_outputs++;
}
}
return num_outputs;
}
int main(){
const char *inputs[] = {
"111abdhsd111gfhds",
"goal!",
"zhd!111oosd",
"111let111"
};
char *outputs[] ={malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000)};
split(outputs, "111", inputs, 4);
for(int i =0; i < 6; i++)
{
printf("The output[%d] is : %s" ,i, outputs[i]);
free(outputs[i]);
}
return 0;
}
NOTE: The following answer refers to revision 2 of the question, which is before OP added code to the question which already uses the function strstr.
If the string is delimited by a substring instead of a single character, you can use the function strstr to find the delimiter substrings:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char input[] = "111adbhsd111gfhds", *p = input;
const char *const delim = "111";
//remember length of delimiter substring
const size_t delim_length = strlen( delim );
for (;;) //infinite loop, equivalent to "while ( 1 )"
{
//attempt to find next delimiter substring
const char *q = strstr( p, delim );
//break loop if this is last token
if ( q == NULL )
break;
//print token
if ( q == p )
printf( "Found token: <empty>\n" );
else
printf( "Found token: %.*s\n", (int)(q-p), p );
//make p point to start of next token
p = q + delim_length;
}
//print last token
printf( "Found token: %s\n", p );
}
This program has the following output:
Found token: <empty>
Found token: adbhsd
Found token: gfhds
Since the sample input starts with the delimiter "111", the first token is empty. If you don't want empty tokens to be printed, you can simply remove the first printf statement in the code.
This is not a full solution to your problem, as your task seems to consist of multiple input strings instead of only one, and writing to output arrays instead of printing to the screen. In accordance with the community guidelines for homework questions, I will not provide a full solution to your problem at this time. Instead, for now, I have only provided a solution to the problem that you stated that you had trouble with (which was using strtok with substring delimiters). If necessary, I can add additional code later.

Using strtok to find pair of token

I am solving this homework problem: Find a pair of adjacent words in the text, such that both words begin in the same letter.
I understand that I need to use strtok function to solve this problem.
#include <string.h>
#include <stdio.h>
#include <conio.h>
int main(void) {
char testString[] = "In the end, we will remember not the words of our enemies, but the silence of our friends";
char *context = testString;
const char *token = strtok_s(testString, ", ", &context);
while (token) {
token = strtok_s(NULL, ", ", &context);
printf(" %s\n", token);
}
_getch();
}
In that case I have two question:
I don't understand why printf starting print from the second word?
What I need to do next to find word pair, how I can get access to letters of token?
You want to find two consecutive tokens which have the same initial character, right?
So you need to store the previous token when retrieving a next one, so that you can compare their initial characters and possibly print them.
Edited: your use of strtok_s seems incorrect. I fixed my mistake in the code below and replaced a wrong use of strtok_s with a correct use of strtok.
#include <string.h>
#include <stdio.h>
int main(void) {
char testString[] = "In the end, we will remember not the words of our enemies, but the silence of our friends";
const char *token_prev = strtok(testString, ", ");
const char *token_next = strtok(NULL, ", ");
while (token_next) {
if (token_next[0] == token_prev[0]) {
printf(" %s %s\n", token_prev, token_next);
// break; // to print the first pair only
}
token_prev = token_next;
token_next = strtok(NULL, ", ");
}
}
See it working at GodBolt: https://godbolt.org/z/YzjcPKrq6
This will iterate through the whole input string and print all pairs found. If you add a break; after printf() under if() then it will print the first pair only.
printf starts printing from the second word because you never print the first token, i.e. the one you've obtained from the initial call to strtok_s before entering the loop.
Token is a regular C string. Its initial letter is token[0], a char. You can store it in a separate char variable, and carry it over into the next iteration of the loop.
Since the words could be in mixed case, you should probably use toupper or tolower when storing and comparing the initial characters.
You extracted the first word in this statement
const char *token = strtok_s(testString, ", ", &context);
but you did not print it. You are starting to print words in the while loop after the preceding call of strtok_s within the loop.
You need two pointers that will point to adjacent extracted strings and using these pointers you can compare first letters of the strings.
Here is a demonstrative program (for simplicity I am using strtok instead of strtok_s)
#include <stdio.h>
#include <string.h>
int main(void)
{
char testString[] = "In the end, we will remember not the words "
"of our enemies, but the silence of our friends";
char *first_word = NULL;
char *second_word = NULL;
const char *delim = ", ";
if ( ( first_word = strtok( testString, delim ) ) != NULL )
{
while ( ( second_word = strtok( NULL, delim ) ) != NULL &&
*first_word != *second_word )
{
first_word = second_word;
}
}
if ( second_word != NULL )
{
printf( "%s <-> %s\n", first_word, second_word );
}
return 0;
}
The program output is
we <-> will
If you want to output all such pairs of words then the program can look the following way
#include <stdio.h>
#include <string.h>
int main(void)
{
char testString[] = "In the end, we will remember not the words "
"of our enemies, but the silence of our friends";
char *first_word = NULL;
char *second_word = NULL;
const char *delim = ", ";
if ( ( first_word = strtok( testString, delim ) ) != NULL )
{
while ( ( second_word = strtok( NULL, delim ) ) != NULL )
{
if ( *first_word == *second_word )
{
printf( "%s <-> %s\n", first_word, second_word );
}
first_word = second_word;
}
}
return 0;
}
The program output is
we <-> will
of <-> our
of <-> our
However instead of using strtok or strtok_s it is much better to use an approach based on the functions strspn and strcspn. In this case you can process constant strings.

Reading particular character from file

I am trying to make a function that reads a text file which contains data and assign it to a variable. However some lines start with $ which need to be ignored. For example:
$ Monday test results
10 12
$ Tuesday test results
4
This is what I have so far which just prints out:
10 12
4
The code that does this is:
#include <stdio.h>
#include <stdlib.h>
void read_data(){
FILE* f;
if (f = fopen("testdata.txt", "r")) {
char line[100];
while (!feof(f)) {
fgets(line, 100, f);
if (line[0] == '$') {
continue;
} else{
puts(line);
}
}
} else {
exit(1);
}
fclose(f);
}
void main(){
read_data();
return 0;
}
I have tried fgetc and have googled extensively but am still stuck ;(
**Edits
Added #include and main
What I am asking is how to assign like a = 10, b = 12, c = 4. Had troubles since using fgets is for lines. Tried fgetc but it would only ignore the actual $ sign not the whole line that the $ is on
C string.h library function - strtok()
char *strtok(char *str, const char *delim)
str − The contents of this string are modified and broken into smaller strings (tokens).
delim − This is the C string containing the delimiters. These may vary from one call to another.
This function returns a pointer to the first token found in the string. A null pointer is returned if there are no tokens left to retrieve.
Copied from: https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
#include <string.h>
#include <stdio.h>
int main () {
char str[80] = "This is - www.tutorialspoint.com - website";
const char s[2] = "-";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}
return(0);
}
Output:
This is
www.tutorialspoint.com
website

What has strtok been replaced with? [duplicate]

#include <stdio.h>
int
main() {
char string[] = "my name is geany";
int length = sizeof(string)/sizeof(char);
printf("%i", length);
int i;
for ( i = 0; i<length; i++ ) {
}
return 0;
}
if i want to print "my" "name" "is" and "geany" separate then what do I do. I was thinking to use a delimnator but i dont know how to do it in C
start with a pointer to the begining of the string
iterate character by character, looking for your delimiter
each time you find one, you have a string from the last position of the length in difference - do what you want with that
set the new start position to the delimiter + 1, and the go to step 2.
Do all these while there are characters remaining in the string...
I needed to do this because the environment was working in had a restricted library that lacked strtok. Here's how I broke up a hyphen-delimited string:
b = grub_strchr(a,'-');
if (!b)
<handle error>
else
*b++ = 0;
c = grub_strchr(b,'-');
if (!c)
<handle error>
else
*c++ = 0;
Here, a begins life as the compound string "A-B-C", after the code executes, there are three null-terminated strings, a, b, and c which have the values "A", "B" and "C". The <handle error> is a place-holder for code to react to missing delimiters.
Note that, like strtok, the original string is modified by replacing the delimiters with NULLs.
This breaks a string at newlines and trims whitespace for the reported strings. It does not modify the string like strtok does, which means this can be used on a const char* of unknown origin while strtok cannot. The difference is begin/end are pointers to the original string chars, so aren't null terminated strings like strtok gives. Of course this uses a static local so isn't thread safe.
#include <stdio.h> // for printf
#include <stdbool.h> // for bool
#include <ctype.h> // for isspace
static bool readLine (const char* data, const char** beginPtr, const char** endPtr) {
static const char* nextStart;
if (data) {
nextStart = data;
return true;
}
if (*nextStart == '\0') return false;
*beginPtr = nextStart;
// Find next delimiter.
do {
nextStart++;
} while (*nextStart != '\0' && *nextStart != '\n');
// Trim whitespace.
*endPtr = nextStart - 1;
while (isspace(**beginPtr) && *beginPtr < *endPtr)
(*beginPtr)++;
while (isspace(**endPtr) && *endPtr >= *beginPtr)
(*endPtr)--;
(*endPtr)++;
return true;
}
int main (void) {
const char* data = " meow ! \n \r\t \n\n meow ? ";
const char* begin;
const char* end;
readLine(data, 0, 0);
while (readLine(0, &begin, &end)) {
printf("'%.*s'\n", end - begin, begin);
}
return 0;
}
Output:
'meow !'
''
''
'meow ?'
use strchr to find the space.
store a '\0' at that location.
the word is now printfable.
repeat
start the search at the position after the '\0'
if nothing is found then print the last word and break out
otherwise, print the word, and continue the loop
Reinventing the wheel is often a bad idea. Learn to use implementation functions is also a good training.
#include <string.h>
/*
* `strtok` is not reentrant, so it's thread unsafe. On POSIX environment, use
* `strtok_r instead.
*/
int f( char * s, size_t const n ) {
char * p;
int ret = 0;
while ( p = strtok( s, " " ) ) {
s += strlen( p ) + 1;
ret += puts( p );
}
return ret;
}

Why does the strchr not take the program into an if condition?

I am trying to run the following code, but during execution, the code does not go into the if condition.
Why does the code not enter the if condition during runtime? I have marked the problem condition.
Running this program on Windows 10.
Thread model: posix
gcc version 5.1.0 (tdm64-1)
I have tried using the ternary operator and the if statement with a different string, and strchr works fine in that case.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main() {
static char str[] = "hello world";
static char inputTime[] = "12:05:10PM";
char *result = strchr(str, 'w');
long int tempNum = 0;
char *token, tempStr[10], delimit[] = ":";
if (strchr(str, 'w'))
printf("\nFound w");
else
printf("\nDid not find w");
(strchr(inputTime, 'P')) ? printf("\nTrue") : printf("\nFalse");
token = strtok(inputTime, delimit);
if (strchr(inputTime, 'P')) {
printf("Found PM\n");
tempNum = strtol(token, NULL, 10);
if (tempNum != 12)
tempNum += 12;
sprintf(tempStr, "%lu", tempNum);
}
printf("\ntempStr: %s", tempStr);
}
The above code gives me this output:
C:\Users\XX\Documents\Tests\c-programming>a.exe
Found w
True
tempStr: σ#
The strtok function splits the given input string into tokens. It does this by modifying the string to tokenize, placing a null byte in place of the delimiter to search for.
So after the call to strtok, inputTime looks like this:
{ '1','2','\0','0','5',':','1','0','P','M','\0' }
A null byte is put in place of the first :. So if you were to print inputTime you would get 12, meaning you won't find a P.
Because the input string is modified, you should search for P before calling strtok.

Resources