I'm trying to tokenize a sting and here is my attempt.
char new_str[1024];
void tokenize_init(const char str[]){//copy the string into global section
strcpy(new_str,str);
}
int i = 0;
char *tokenize_next() {
const int len = strlen(new_str);
for(; i <= len; i++) {
if ( i == len) {
return NULL;
}
if ((new_str[i] >= 'a' && new_str[i] <= 'z') ||
(new_str[i] >= 'A' && new_str[i] <= 'Z')) {
continue;
}else {
new_str[i] = '\0';
i = i + 1;
return new_str;
}
}
return NULL;
}
//main function
int main(void) {
char sentence[] = "This is a good-sentence for_testing 1 neat function.";
printf("%s\n", sentence);
tokenize_init(sentence);
for (char *nt = tokenize_next();
nt != NULL;
nt = tokenize_next())
printf("%s\n",nt);
}
However, it just print out the first word of the sentence(which is "This") and then stop. Can someone tell me why? My guess is my new_str is not persisent and when the main function recall tokenize_next() the new_str become just the first word of the sentence. Thanks in advance.
The reason that it only prints out "This" is because you iterate to the first non-letter character which happens to be a space, and you replace this with a null terminating character at this line:
new_str[i] = '\0';
After that, it doesn't matter what you do to the rest of the string, it will only print up to that point. The next time tokenize_next is called the length of the string is no longer what you think it is because it is only counting the word "This" and since "i" has already reached that amount the function returns and so does every successive call to it:
if ( i == len)
{
return NULL;
}
To fix the function you would need to somehow update your pointer to look past that character on the next iteration.
However, this is quite kludgy. You are much better off using one of the mentioned functions such as strtok or strsep
UPDATE:
If you cannot use those functions then a redesign of your function would be ideal, however, per your request, try the following modifications:
#include <string.h>
#include <cstdio>
char new_str[1024];
char* str_accessor;
void tokenize_init(const char str[]){//copy the string into global section
strcpy(new_str,str);
str_accessor = new_str;
}
int i = 0;
char* tokenize_next(void) {
const int len = strlen(str_accessor);
for(i = 0; i <= len; i++) {
if ( i == len) {
return NULL;
}
if ((str_accessor[i] >= 'a' && str_accessor[i] <= 'z') ||
(str_accessor[i] >= 'A' && str_accessor[i] <= 'Z')) {
continue;
}
else {
str_accessor[i] = '\0';
char* output = str_accessor;
str_accessor = str_accessor + i + 1;
if (strlen(output) <= 0)
{
str_accessor++;
continue;
}
return output;
}
}
return NULL;
}
//main function
int main(void) {
char sentence[] = "This is a good-sentence for_testing 1 neater function.";
printf("%s\n", sentence);
tokenize_init(sentence);
for (char *nt = tokenize_next(); nt != NULL; nt = tokenize_next())
printf("%s\n",nt);
}
Related
I am in the stage of preparing myself for exams, and the thing that I m least proud of are my skills with strings. What I need to do is remove a word from a sentence, without using <string.h> library at all.
This is what I've got so far. It keeps showing me that certain variables are not declared, such as start and end.
#include <stdio.h>
/* Side function to count the number of letters of the word we wish to remove */
int count(char *s) {
int counter = 0;
while (*s++) {
counter++;
s--;
return counter;
}
/* Function to remove a word from a sentence */
char *remove_word(const char *s1, const char *s2) {
int counter2 = 0;
/* We must remember where the string started */
const char *toReturn = s1;
/* Trigger for removing the word */
int found = 1;
/* First we need to find the word we wish to remove [Don't want to
use string.h library for anything associated with the task */
while (*s1 != '\0') {
const char *p = s1;
const char *q = s2;
if (*p == *q)
const char *start = p;
while (*p++ == *q++) {
counter2++;
if (*q != '\0' && counter2 < count(s2))
found = 0;
else {
const char *end = q;
}
}
/* Rewriting the end of a sentence to the beginning of the found word */
if (found) {
while (*start++ = *end++)
;
}
s1++;
}
return toReturn;
}
void insert(char niz[], int size) {
char character = getchar();
if (character == '\n')
character = getchar();
int i = 0;
while (i < size - 1 && character != '\n') {
array[i] = character;
i++;
character = getchar();
}
array[i] = '\0';
}
int main() {
char stringFirst[100];
char stringSecond[20];
printf("Type your text here: [NOT MORE THAN 100 CHARACTERS]\n");
insert(stringFirst, 100);
printf("\nInsert the word you wish to remove from your text.");
insert(stringSecond, 20);
printf("\nAfter removing the word, the text looks like this now: %s", stringFirst);
return 0;
}
your code is badly formed, i strongly suggest compiling with:
gcc -ansi -Wall -pedantic -Werror -D_DEBUG -g (or similar)
start with declaring your variables at the beginning of the function block, they are known only inside the block they are declared in.
your count function is buggy, missing a closing '}' (it doesn't compile)
should be something like
size_t Strlen(const char *s)
{
size_t size = 0;
for (; *s != '\n'; ++s, ++size)
{}
return size;
}
implementing memmove is much more efficient then copy char by char
I reformatted you code for small indentation problems and indeed indentation problems indicate real issues:
There is a missing } in count. It should read:
/* Side function to count the number of letters of the word we wish to remove */
int count(char *s) {
int counter = 0;
while (*s++) {
counter++;
}
return counter;
}
or better:
/* Side function to count the number of letters of the word we wish to remove */
int count(const char *s) {
const char *s0 = s;
while (*s++) {
continue;
}
return s - s0;
}
This function counts the number of bytes in the string, an almost exact clone of strlen except for the return type int instead of size_t. Note also that you do not actually use nor need this function.
Your function insert does not handle EOF gracefully and refuses an empty line. Why not read a line with fgets() and strip the newline manually:
char *input(char buf[], size_t size) {
size_t i;
if (!fgets(buf, size, stdin))
return NULL;
for (i = 0; buf[i]; i++) {
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
}
return buf;
}
In function remove_word, you should define start and end with a larger scope, typically the outer while loop's body. Furthermore s1 should have type char *, not const char *, as the phrase will be modified in place.
You should only increment p and q if the test succeeds and you should check that p and q are not both at the end of their strings.
last but not least: you do not call remove_word in the main function.
The complete code can be simplified into this:
#include <stdio.h>
/* Function to remove a word from a sentence */
char *remove_word(char *s1, const char *s2) {
if (*s2 != '\0') {
char *dst, *src, *p;
const char *q;
dst = src = s1;
while (*src != '\0') {
for (p = src, q = s2; *q != '\0' && *p == *q; p++, q++)
continue;
if (*q == '\0') {
src = p; /* the word was found, skip it */
} else {
*dst++ = *src++; /* otherwise, copy this character */
}
}
*dst = '\0'; /* put the null terminator if the string was shortened */
}
return s1;
}
char *input(char buf[], size_t size) {
size_t i;
if (!fgets(buf, size, stdin))
return NULL;
for (i = 0; buf[i]; i++) {
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
}
return buf;
}
int main() {
char stringFirst[102];
char stringSecond[22];
printf("Type your text here, up to 100 characters:\n");
if (!input(stringFirst, sizeof stringFirst))
return 1;
printf("\nInsert the word you wish to remove from your text: ");
if (!input(stringSecond, sizeof stringSecond))
return 1;
printf("\nAfter removing the word, the text looks like this now: %s\n",
remove_word(stringFirst, stringSecond));
return 0;
}
Your start and end pointers are defined within a block which makes their scope limited within that block. So, they are not visible to other parts of your code, and if you attempt to reference them outside their scope, the compiler will complain and throw an error. You should declare them at the beginning of the function block.
That said, consider the following approach to delete a word from a string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int delete_word(char *buf,
const char *word);
int main(void)
{
const char word_to_delete[] = "boy";
fputs("Enter string: ", stdout);
char buf[256];
fgets(buf, sizeof(buf), stdin);
if (delete_word(buf, word_to_delete))
{
printf("Word %s deleted from buf: ", word_to_delete);
puts(buf);
}
else
{
printf("Word %s not found in buf: ", word_to_delete);
puts(buf);
}
system("PAUSE");
return 0;
}
int chDelimit(int ch)
{
return
(ch == '\n' || ch == '\t') ||
(ch >= ' ' && ch <= '/') ||
(ch >= ':' && ch <= '#') ||
(ch >= '[' && ch <= '`') ||
(ch >= '{' && ch <= '~') ||
(ch == '\0');
}
char *find_pattern(char *buf,
const char *pattern)
{
size_t n = 0;
while (*buf)
{
while (buf[n] && pattern[n])
{
if (buf[n] != pattern[n])
{
break;
}
n++;
}
if (!pattern[n])
{
return buf;
}
else if (!*buf)
{
return NULL;
}
n = 0;
buf++;
}
return NULL;
}
char *find_word(char *buf,
const char *word)
{
char *ptr;
size_t wlen;
wlen = strlen(word);
ptr = find_pattern(buf, word);
if (!ptr)
{
return NULL;
}
else if (ptr == buf)
{
if (chDelimit(buf[wlen]))
{
return ptr;
}
}
else
{
if (chDelimit(ptr[-1]) &&
chDelimit(ptr[wlen]))
{
return ptr;
}
}
ptr += wlen;
ptr = find_pattern(ptr, word);
while (ptr)
{
if (chDelimit(ptr[-1]) &&
chDelimit(ptr[wlen]))
{
return ptr;
}
ptr += wlen;
ptr = find_pattern(ptr, word);
}
return NULL;
}
int delete_word(char *buf,
const char *word)
{
size_t n;
size_t wlen;
char *tmp;
char *ptr;
wlen = strlen(word);
ptr = find_word(buf, word);
if (!ptr)
{
return 0;
}
else
{
n = ptr - buf;
tmp = ptr + wlen;
}
ptr = find_word(tmp, word);
while (ptr)
{
while (tmp < ptr)
{
buf[n++] = *tmp++;
}
tmp = ptr + wlen;
ptr = find_word(tmp, word);
}
strcpy(buf + n, tmp);
return 1;
}
If you have to do it manually, just loop over the indicies of your string to find the first one that matches and than you’ll have a second loop that loops for all the others that matches and resets all and jumps to the next index of the first loop if not matched something in order to continue the searching. If I recall accuretaly, all strings in C are accesible just like arrays, you’ll have to figure it out how. Don’t afraid, those principles are easy! C is an easy langugae, thiught very long to write.
In order to remove: store the first part in an array, store the second part in an array, alloc a new space for both of them and concatinate them there.
Thanks, hit the upvote button.
Vitali
EDIT: use \0 to terminate your newly created string.
I have a string and an array of keywords. If the string contains one of the keywords on the list, I want to check if the keyword is the only element of this string. If it's not, I want to return an error. Last thing, the string will always end with \n.
My keyword array is the following:
const char * keywordsTable[] =
{
"INIT",
"BEGIN",
"END",
"ROUTINES",
"ENDROUTINES",
"ENDWHEN",
"WHEN",
"WHILE"
};
For instance if my string is "BEGIN\n", everything is fine. If my string is "BEGIN FOO\n" or "FOO BEGIN\n", I have to return an error. Finally if my string is "BEGINFOO\n", everything is fine. (error code is 1, else it's 0)
I've tried something (I don't know how to proceed):
int CheckKeyword(char * str)
{
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char * strTok = NULL;
char * keywrdWithLF = malloc(20);
// I don't want to check for the last two keywords nor the first
for (int i = 1; i < nKeywords - 2; i++)
{
strcpy_s(keywrdWithLF, 20, keywordsTable[i]);
strcat_s(keywrdWithLF, 20, "\n");
strTok = strstr(str, keywrdWithLF);
// If my string contains a keyword
if (strTok != NULL)
{
// If the string contains other characters... and I'm stuck
if (strcmp(str, keywrdWithLF))
{
}
else
{
free(keywrdWithLF);
return 1;
}
}
}
free(keywrdWithLF);
return 0;
}
Thank you in advance (please don't complain bout my indent style, I have to use Whitesmith indent) !
int CheckKeyword(char * str)
{
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char * strTok = NULL;
for (int i = 1; i < nKeywords - 2; i++)
{
if(NULL!=(strTok = strstr(str, keywordsTable[i])))
{
int len = strlen(keywordsTable[i]);
if(strTok == str)
{
if(str[len]==' ' || str[len]=='\t')
return 1;
}
else
{
if((strTok[-1]==' ' || strTok[-1]=='\t') && isspace(strTok[len]))//isspace in <ctype.h>
return 1;
}
}
}
return 0;
}
Perhaps another method?
int CheckKeyword(char * str)
{
int rCode=0;
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char *keyword;
char *cp = keywordsTable;
I assume that since str is defined as "char * str" and not "const char * str", it is OK to modify the input string. Hence, why not just eliminate the '\n' problem from the equation?
/* Elininate the newline character from the end of the string. */
if((cp = strchr(str, '\n'))
*cp = \0;
// I don't want to check for the last two keywords nor the first.
nKeywords -= 3;
++keyword;
/* Loop through the keywords. */
while(nKeywords)
{
// "I want to check if the keyword is the only element of this string."
// "If it's not, I want to return an error."
if((cp=strstr(str, keyword))
{
/* Check for stuff prior to the keyword. */
if(cp != str)
rCode=1;
/* Check for stuff after the keyword. */
// Finally if my string is "BEGINFOO\n", everything is fine.
if(' ' == str[strlen[keyword])
rCode=1;
if(strcmp(cp, keyword))
rCode=1
break;
}
++keyword;
--nKeywords;
}
return(rCode);
}
I am trying to write a function that will allow me to use a function I wrote called strLength to count a number of characters passed, then will mallocate the number in addition to a NULL terminator, then copy the characters and return the copy.
so far I have:
int strLength(char* toCount)
{
int count = 0;
while(*toCount != '\0')
{
count++;
toCount++;
}
return count;
}
char* strCopy(char *s)
{
int length = strLength(s);
char *copy = malloc(length+1);
while(s != '\0')
{
s++;
}
return copy;
}
strCopy is the function I need help with. I also can not use strcpy or memcpy, I'm just writing this on my own to create my own string library. I think before the s++ I should have something along the lines of copy += s but I am not sure that would work.
I am a bit of a newbie, so please bear with me
Copy from the end to the beginning looks like a quick approach.
Check for a NULL allocation.
char* strCopy(char *s) {
int length = strLength(s) + 1;
char *copy = malloc(length);
if (copy != NULL) {
while (length > 0) {
length--;
copy[length] = s[length];
}
}
return copy;
}
Try this. Its working for me. I hope this helps.
char* strCopy(char *s)
{
char *copy = (char*) malloc(strLength(s) + 1);
int index = 0;
while(s[index] != '\0')
{
copy[index] = s[index];
index++;
}
return copy;
}
I am trying to create a function that removes a specified character from a string.
I am only halfway done with the code because I got stuck when I am trying to replace the character to delete with nothing. I just realized I can't put "nothing" in an element of an array so my plan just got ruined.
I figure that I have to loop through the whole string, and when I find the character I want to remove I have to remove it by moving all of the elements that are in front of the "bad" character one step back. Is that correct?
#include <stdio.h>
#include <string.h>
void del(char string[], char charToDel)
{
int index = 0;
while(string[index] != '\0')
{
if(string[index] == charToDel){
string[index] = string[index+1];
}
index++;
}
printf("%s", string);
}
int main(void)
{
char string[] = "Hello world";
del(string, 'l');
return 0;
}
I want to make this program without pointers. Just plain simple code.
I added another while loop that moves every character in the loop to the left but it doesn't seem to work since the output is just plain blank.
int index = 0;
while(string[index] != '\0')
{
if(string[index] == charToDel)
{
while(string[index] != '\0')
{
string[index] = string[index+1];
}
}
index++;
}
printf("%s", string);
}
Johathan Leffler's Method?
char newString[100];
int index = 0;
int i = 0;
while(string[index] != '\0')
{
if(string[index] != charToDel)
{
newString[i] = string[index];
index++;
i++;
}
i++;
index++;
}
printf("%s", newString);
}
This gives me a lot of weird characters...
char const *in = string;
char *out = string;
while (*in) {
if (*in != charToDel)
*out++ = *in;
++in;
}
*out = '\0';
or without pointers
size_t in = 0;
size_t out = 0;
while (string[in]) {
if (string[in] != charToDel)
string[out++] = string[in];
++in;
}
string[out] = '\0';
The problem is that, when you are assigning string[index+1] to string[index], the next l from the string took place of previous one and index incremented to its next value by 1and this l is not deleted by your function. You should have to fixed that.
As suggested by Jonathan Leffler and Gabson; you can do it by coping the string to itself as;
void del(char string[], char charToDel)
{
int index = 0, i = 0;
while(string[index] != '\0')
{
if(string[index] != charToDel){
string[i++] = string[index];
}
index++;
}
string[i] = '\0';
printf("%s", string);
}
I have a string and I want to remove all the punctuation from the beginning and the end of it only, but not the middle.
I have wrote a code to remove the punctuation from the first and last character of a string only, which is clearly very inefficient and useless if a string has 2 or more punctuations at the end.
Here is an example:
{ Hello ""I am:: a Str-ing!! }
Desired output
{ Hello I am a Str-ing }
Are there any functions that I could use? Thanks.
This is what I've done so far. I'm actually editing the string in a linked-list
if(ispunct(removeend->string[(strlen(removeend->string))-1]) != 0) {
removeend->string[(strlen(removeend->string))-1] = '\0';
}
else {}
Iterate over the string, use isalpha() to check each character, write the characters which pass into a new string.
char *rm_punct(char *str) {
char *h = str;
char *t = str + strlen(str) - 1;
while (ispunct(*p)) p++;
while (ispunct(*t) && p < t) { *t = 0; t--; }
/* also if you want to preserve the original address */
{ int i;
for (i = 0; i <= t - p + 1; i++) {
str[i] = p[i];
} p = str; } /* --- */
return p;
}
Iterate over the string, use isalpha() to check each character, after the first character that passes start writing into a new string.
Iterate over the new string backwards, replace all punctuation with \0 until you find a character which isn't punctuation.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
char* trim_ispunct(char* str){
int i ;
char* p;
if(str == NULL || *str == '\0') return str;
for(i=strlen(str)-1; ispunct(str[i]);--i)
str[i]='\0';
for(p=str;ispunct(*p);++p);
return strcpy(str, p);
}
int main(){
//test
char str[][16] = { "Hello", "\"\"I", "am::", "a", "Str-ing!!" };
int i, size = sizeof(str)/sizeof(str[0]);
for(i = 0;i<size;++i)
printf("%s\n", trim_ispunct(str[i]));
return 0;
}
/* result:
Hello
I
am
a
Str-ing
*/
Ok, in a while iteration, call multiple times the strtok function to separate each single string by the character (white space). You could also use sscanf instead of strtok.
Then, for each string, you have to do a for cycle, but beginning from the end of the string up to the beginning.As soon as you encounter !isalpha(current character) put a \0 in the current string position. You have eliminated the tail's punctuation chars.
Now, do another for cycle on the same string. Now from 0 to strlen(currentstring). While is !isalpha(current character) continue. If isalpha put the current character in in a buffer and all the remaining characters. The buffer is the cleaned string. Copy it into the original string.
Repeat the above two steps for the others strtok's outputs. End.
Construct a tiny state machine. The cha2class() function divides the characters into equivalence classes. The state machine will always skip punctuation, except when it has alphanumeric characters on the left and the right; in that case it will be preserved. (that is the memmove() in state 3)
#include <stdio.h>
#include <string.h>
#define IS_ALPHA 1
#define IS_WHITE 2
#define IS_PUNCT 3
int cha2class(int ch);
void scrutinize(char *str);
int cha2class(int ch)
{
if (ch >= 'a' && ch <= 'z') return IS_ALPHA;
if (ch >= 'A' && ch <= 'Z') return IS_ALPHA;
if (ch == ' ' || ch == '\t') return IS_WHITE;
if (ch == EOF || ch == 0) return IS_WHITE;
return IS_PUNCT;
}
void scrutinize(char *str)
{
size_t pos,dst,start;
int typ, state ;
state = 0;
for (dst = pos = start=0; ; pos++) {
typ = cha2class(str[pos]);
switch(state) {
case 0: /* BOF, white seen */
if (typ==IS_WHITE) break;
else if (typ==IS_ALPHA) { start = pos; state =1; }
else if (typ==IS_PUNCT) { start = pos; state =2; continue;}
break;
case 1: /* inside a word */
if (typ==IS_ALPHA) break;
else if (typ==IS_WHITE) { state=0; }
else if (typ==IS_PUNCT) { start = pos; state =3;continue; }
break;
case 2: /* inside punctuation after whitespace: skip it */
if (typ==IS_PUNCT) continue;
else if (typ==IS_WHITE) { state=0; }
else if (typ==IS_ALPHA) {state=1; }
break;
case 3: /* inside punctuation after a word */
if (typ==IS_PUNCT) continue;
else if (typ==IS_WHITE) { state=0; }
else if (typ==IS_ALPHA) {
memmove(str+dst, str+start, pos-start); dst += pos-start;
state =1; }
break;
}
str[dst++] = str[pos];
if (str[pos] == '\0') break;
}
}
int main (int argc, char **argv)
{
char test[] = ".This! is... ???a.string?" ;
scrutinize(test);
printf("Result=%s\n", test);
return 0;
}
int main (int argc, char **argv)
{
char test[] = ".This! is... ???a.string?" ;
scrutinize(test);
printf("Result=%s\n", test);
return 0;
}
OUTPUT:
Result=This is a.string