function that removes spaces and tabs - c

im trying to make a function that removes spaces and tabs from a given string except for the first tab or space in the string. when im using my function it removes the spaces and tabs except for the first one but it also removes the first letter after the first space or tab.
for example > "ad ad ad"> "ad dad" instead of "ad adad"
why is that?
void RemoveSpacetab(char* source) {
char* i = source;
char* j = source;
int spcflg = 0;
while(*j != 0) {
*i = *j++;
if((*i != ' ') && (*i != '\t'))
i++;
if(((*i == ' ') || (*i == '\t')) && (spcflg == 0)) {
i++;
spcflg = 1;
}
}
*i = 0;
}

You will need to separate your source and destination arrays as they will become different lengths. You could find the starting position before copying characters like this, lets say you pass the source and the length of the source as char* source, int length (you could also calculate the length of the source with strlen(source), then your function could look like this:
int i = 0;
char* dest = malloc(sizeof(char) * length);
// Increment i until not space to find starting point.
while (i < length && (source[i] == '\t' || source[i] == ' ')) i++;
int dest_size = 0;
while (i < length) {
if (source[i] != '\t' && source[i] != ' ') {
// Copy character if not space to dest array
dest[dest_size++] = source[i];
}
i++;
}
dest[dest_size++] = 0; // null terminator
// Feel free to realloc to the right length with
// realloc(dest, dest_size * sizeof(char))
return dest;

The problem caused by two if statements one after the other. Your i precedes j when you detect a space for first time.
Explanation:
In first cycle the i points to position 0 and j too. The 'a' at position 0 will be overwritten with itself then j moves onwards to position 1. Your first if block finds out that the character at position 0 is not a space and not a tab, so moves the i to position 1.
In second cycle the 'b' will be overwritten with itself then j moves to position 2 which is a space. The first if finds out that 'b' at position 1 is not a space and not a tab so moves the i to position 2. Now the second if finds out that the i points to a space for first time and moves it to the position 3 while j is still points to the position 2.
In third cycle the 'a' at position 3 will be overwritten with the space at position 2 and j catches up with i.
A possible fix to your code:
#include <stdio.h>
void RemoveSpacetab(char* source) {
char* i = source;
char* j = source;
char spcflg = 0;
while(*j != 0) {
*i = *j++;
if(*i == ' ' || *i == '\t') {
if(!spcflg) {
i++;
spcflg = 1;
}
}
else {
i++;
}
}
*i = 0;
}
int main() {
char my_string[] = "ad ad ad";
RemoveSpacetab(my_string);
printf("%s\n", my_string);
return 0;
}

Related

How to Replace Leading or Trailing Blank Characters with "X"

Looking for a more efficient way to replace leading and trailing empty spaces (' ') and appending an 'X' to the front for each empty space.. It seems to work ok for trailing spaces but I'd like to know if there's a better / simpler way of going about this that I am missing.
Example:
Passed in string: '12345 '
Desired result 'XXXXX12345'
Removed 5 empty spaces and append 5 'X's to front.
Example:
Passed in string: ' 12345'
Desired result 'XX12345'
Remove 2 empty spaces and append 2 'X's to front.
void fixStr(char* str)
{
int i = 0;
int length = strlen(str);
char strCopy[10];
strcpy(strCpy, str);
for(i = 0; i < length; i++)
{
if(strCopy[i] == ' ')
{
strCopy[i] = '\0';
str[i] = '\0';
break;
}
}
for(i = 0; i < length - i + 2; i++)
{
str[i] = 'X';
str[i + 1] = '\0';
}
strcat(str, strCopy);
}
One way to achieve this is to find out the leading non-space position & trailing non-space position of the string, and then move the content in-between (leading nonspace, trailing nonspace) this to end of the string, then set all the empty space at the beginning to 'x'
This way you can get the expected output (function below)
void fixStr(char* str)
{
int i = 0;
int length = strlen(str);
int leadindex = length;
int tailindex = 0;
// First find the leading nonspace position
for(i = 0; i < length; i++)
{
if(str[i] != ' ')
{
leadindex = i;
break;
}
}
// if not found nonspace then no change
if( leadindex == length )
{
// all spaces, so no change required;
return;
}
// Find the trailing nonspace position
for(i = length - 1; i >= 0 ; i--)
{
if(str[i] != ' ')
{
tailindex = i;
break;
}
}
// move the buffer (in place) to exclude trailing spaces
memmove(str + (length - tailindex -1),str,(tailindex +1) );
// set the 'x' to all empty spaces at leading ( you may use for loop to set this)
memset(str, 'X', length - (tailindex - leadindex + 1) );
}
To solve a problem the engineer's way:
Define the needs.
Know your tools.
Use the tools as simple as possible, as accurate as necessary to make up a solution.
In your case:
Needs:
find the number of trailing spaces
move content of string to the end
set beginning to 'X's
Tools:
to measure, iterate, compare and count
to move a block of memory
to initialise a block of memory
Example for a solution:
#include <string.h> /* for strlen(), memmove () and memset() */
void fix_str(char * s)
{
if ((NULL != s) && ('\0' != *s)) /* Ignore NULL and empty string! */
{
/* Store length and initialise counter: */
size_t l = strlen(s), i = l;
/* Count space(s): */
for (; (0 != i) && (' ' == s[i-1]); --i); /* This for loop does not need a "body". */
/* Calculate the complement: */
size_t c = l - i;
/* Move content to the end overwriting any trailing space(s) counted before hand: */
memmove(s+c, s, i); /* Note that using memmove() instead of memmcpy() is essential
here as the source and destination memory overlap! */
/* Initialise the new "free" characters at the beginning to 'X's:*/
memset(s, 'X', c);
}
}
I didn't fix your code but you could use sprintf in combination with isspace, something along the lines of this. Also, remember to make a space for the '\0 at the end of your string. Use this idea and it should help you:
#include <ctype.h>
#include <stdio.h>
int main()
{
char buf[11];
char *s = "Hello";
int i;
sprintf(buf, "%10s", s); /* right justifies in a column of 10 in buf */
for(i = 0; i < 10; i++) {
if(isspace(buf[i])) /* replace the spaces with an x (or whatever) */
buf[i] = 'x';
}
printf("%s\n", buf);
return 0;
}

Trying to delete a specific character from a string in C?

I'm trying to delete a specific character (?) from the end of a string and return a pointer to a string, but it's not removing it at all at the moment. What am I doing wrong? Is there a better way to go about it?
char * word_copy = malloc(strlen(word)+1);
strcpy(word_copy, word);
int length = strlen(word_copy);
int i = 0;
int j = 0;
for (i = 0; word_copy[i] != '\0'; i++) {
if (word_copy[length - 1] == '?' && i == length - 1){
break;
}
}
for (int j = i; word_copy[j] != '\0'; j++) {
word_copy[j] = word_copy[j+1];
}
word = strdup(word_copy);
I'm immediately seeing a couple of problems.
The first for loop does nothing. It doesn't actually depend on i so it could be replaced with a single if statement.
if (word_copy[length - 1] == '?') {
i = length - 1;
} else {
i = length + 1;
}
The second for loop also acts as an if statement since it starts at the end of the string and can only ever run 0 or 1 times.
You could instead do something like this to remove the ?. This code will return a new malloced string with the last character removed if its ?.
char *remove_question_mark(char *word) {
unsigned int length = strlen(word);
if (length == 0) {
return calloc(1, 1);
}
if (word[length - 1] == '?') {
char *word_copy = malloc(length);
// Copy up to '?' and put null terminator
memcpy(word_copy, word, length - 1);
word_copy[length - 1] = 0;
return word_copy;
}
char *word_copy = malloc(length + 1);
memcpy(word_copy, word, length + 1);
return word_copy;
}
Or if you are feeling lazy, you could also just make the last character the new null terminator instead. Its essentially creates a memory leak of 1 byte, but that may be an acceptable loss. It should also be a fair bit faster since it doesn't need to allocate any new memory or copy the previous string.
unsigned int length = strlen(word);
if (length > 0 && word[length - 1] == '?') {
word[length] = 0;
}

Swap words of a string without using sting library and use pointers

The goal of my exercise is to produce
The original string is:
silence .is a looking bird:the turning; edge, of life. e. e. cummings
Destination string after swapping:
cummings e. e. life. of edge, turning; bird:the looking a .is silence
and what I am getting is:
69The original string is:
silence .is a looking bird:the turning; edge, of life. e. e. cummings
Destination string after swapping:
my code:
'''
#include<stdio.h>
#include<stdlib.h>
#define MAX_STR_LEN 1024
// DO NOT USE the string library <string.h> for this exercise
void wordSwapper(char *source, char *destination)
{
int count = 0;
while (*(source + count) != '\0')
{
count++;
}
printf("%d", count);
for(int i = 0; i < count; i++)
{
*(destination + i) = *(source + (count - i));
}
}
int main()
{
char source[MAX_STR_LEN]="silence .is a looking bird:the turning; edge, of life. e. e. cummings";
char destination[MAX_STR_LEN]="I am a destination string and I contain lots of junk 1234517265716572#qsajdkuhasdgsahiehwjauhiuiuhdsj!";
wordSwapper(&source[0], &destination[0]);
printf("The original string is: \n%s\n",source);
printf("Destination string after swapping: \n%s\n",destination);
}
'''
My variant:
void wordSwapper(char *source, char *destination)
{
char *start, *end;
start = source;
while (*(start++) != '\0')
destination++;
// write trailing zero
*destination = '\0';
while (*source != '\0')
{
// copy spaces
while (*source == ' ')
*(--destination) = *(source++);
// find word bounds
start = end = source;
while (*end != '\0' && *end != ' ')
end++;
source = end;
// copy word
while (end > start)
*(--destination) = *(--end);
}
}
The posted code reverse the string - character by character. Two issues:
off-by-one, where the terminating NUL character is copied to position 0 of the destination string, therefore the result is empty string. The sec
The requirement is to split the string into words, and copy the words in reverse order to the destination string.
Consider the following alternative
void wordSwapper2(char *source, char *destination)
{
int count = 0;
while (*(source + count) != '\0')
{
count++;
}
// Copy words in reverse order
char *dest = destination ;
int dest_pos = 0 ;
// Word End
int w_end = count ;
while ( w_end >= 0 ) {
// Find word start
int w_start = w_end ;
while ( w_start > 0 && source[w_start-1] != ' ' ) w_start-- ;
// Copy word
for (int i=w_start ; i<w_end ; i++ ) *dest++ = source[i] ;
// Add space if not first word
if ( w_start > 0 ) *dest++ = ' ' ;
// Move to previous word (skip over space)
w_end = w_start-1 ;
} ;
// Terminating NUL
*dest++ = '\0' ;
}

How do I convert an underscored pointer to a char array into camelCasing?

I am trying to write a function that will convert a "word_string" to "wordString". However, my output from the code below is "wordSttring". I'm having trouble skipping to the next element of the array after I replace the undescore with the uppercase of the next element. Any suggestions?
void convert_to_camel(char* phrase){
int j =0;
for(int i=0;i<full_len-1;i++){
if(isalphanum(phrase[i])){
phrase[j] = phrase[i];
j++;
length++;
}
}
int flag = 0;
char new[50];
for (int i=0;i<length;i++){
if(phrase[i]== '95'){
flag = 1;
}
if(flag ==1){
new[i] = toUpper(phrase[i+1]);
i++;
new[i] = phrase[i+1];
flag = 0;
}
else{
new[i] = phrase[i];
}
}
All other solutions presented so far turn "_" into an empty string and remove _ from the end of the string.
#include <stddef.h>
#include <ctype.h>
void to_camel_case(char *str) // pun_intended
{
for (size_t i = 0, k = 0; str[i]; ++i, ++k)
{
while (k && str[k] == '_' && str[k + 1]) // 1)
str[k] = k - 1 ? toupper((char unsigned)str[++k]) : str[++k]; // 2)
str[i] = str[k];
}
}
Skip consecutive '_'. Make sure to leave at least one at the beginning and one at the end of the string if present.
Replace '_' with the next character, capitalized if needed.
You are not handling the removing _ properly for that you need one more loop index(j).
And you don't need one more loop to remove the non alpha numeric chars it can be done with _ loop only,
also you need to terminate the string once trimming is completed otherwise your string will have junk chars.
void toCamelCase(char* phrase){
int j=0;
for (int i=0;i<strlen(phrase);i++){
if(phrase[i] != '_' && isalnum(phrase[i])){ //Copy Alpha numeric chars not including _.
phrase[j++] = phrase[i];
}
else if(phrase[i] == '_'){
phrase[j++] = toupper(phrase[i+1]);
i++;
}
}
phrase[j] = '\0'; //Terminate the string
}
Note::This method does not handle consecutive _(word____string).
Note that in your current implementation you are trying to use new character array to store the processed string but you won't be able to use it outside that function since it is local variable and its end of life is the very moment the flow exits that function.
Here is my proposal for such function:
#define MAX_STR_LEN 50
// assuming that 'str' is a null terminated string
void to_camel_case(char *str)
{
int idx = 0;
int newIdx = 0;
int wasUnderscore = 0;
// just to be on the safe side
if (!str || strlen(str) >= MAX_STR_LEN)
return;
while (str[idx])
{
if (str[idx] == '_')
{
idx++;
// no copy in this case, just raise a flag that '_' was met
wasUnderscore = 1;
}
else if (wasUnderscore)
{
// next letter after the '_' should be uppercased
str[newIdx++] = toupper(str[idx++]);
// drop the flag which indicates that '_' was met
wasUnderscore = 0;
}
else
{
// copy the character and increment the indices
str[newIdx++] = str[idx++];
}
}
str[newIdx] = '\0';
}
I tested it with some inputs and this is what I got:
String hello_world became helloWorld
String hello___world became helloWorld
String hel_lo_wo_rld__ became helLoWoRld
String __hello_world__ became HelloWorld
Maybe something like this might help :
void toCamelCase(char* phrase){
int length = strlen(phrase);
int res_ind = 0;
for (int i = 0; i < length ; i++) {
// check for underscore in the sentence
if (phrase[i] == '_') {
// conversion into upper case
phrase[i + 1] = toupper(s[i + 1]);
continue;
}
// If not space, copy character
else
phrase[res_ind++] = s[i];
}
phrase[res_ind] = '\0';
}

Parsing character array to words held in pointer array (C-programming)

I am trying to separate each word from a character array and put them into a pointer array, one word for each slot. Also, I am supposed to use isspace() to detect blanks. But if there is a better way, I am all ears. At the end of the code I want to print out the content of the parameter array.
Let's say the line is: "this is a sentence". What happens is that it prints out "sentence" (the last word in the line, and usually followed by some random character) 4 times (the number of words). Then I get "Segmentation fault (core dumped)".
Where am I going wrong?
int split_line(char line[120])
{
char *param[21]; // Here I want to put one word for each slot
char buffer[120]; // Word buffer
int i; // For characters in line
int j = 0; // For param words
int k = 0; // For buffer chars
for(i = 0; i < 120; i++)
{
if(line[i] == '\0')
break;
else if(!isspace(line[i]))
{
buffer[k] = line[i];
k++;
}
else if(isspace(line[i]))
{
buffer[k+1] = '\0';
param[j] = buffer; // Puts word into pointer array
j++;
k = 0;
}
else if(j == 21)
{
param[j] = NULL;
break;
}
}
i = 0;
while(param[i] != NULL)
{
printf("%s\n", param[i]);
i++;
}
return 0;
}
There are many little problems in this code :
param[j] = buffer; k = 0; : you rewrite at the beginning of buffer erasing previous words
if(!isspace(line[i])) ... else if(isspace(line[i])) ... else ... : isspace(line[i]) is either true of false, and you always use the 2 first choices and never the third.
if (line[i] == '\0') : you forget to terminate current word by a '\0'
if there are multiple white spaces, you currently (try to) add empty words in param
Here is a working version :
int split_line(char line[120])
{
char *param[21]; // Here I want to put one word for each slot
char buffer[120]; // Word buffer
int i; // For characters in line
int j = 0; // For param words
int k = 0; // For buffer chars
int inspace = 0;
param[j] = buffer;
for(i = 0; i < 120; i++) {
if(line[i] == '\0') {
param[j++][k] = '\0';
param[j] = NULL;
break;
}
else if(!isspace(line[i])) {
inspace = 0;
param[j][k++] = line[i];
}
else if (! inspace) {
inspace = 1;
param[j++][k] = '\0';
param[j] = &(param[j-1][k+1]);
k = 0;
if(j == 21) {
param[j] = NULL;
break;
}
}
}
i = 0;
while(param[i] != NULL)
{
printf("%s\n", param[i]);
i++;
}
return 0;
}
I only fixed the errors. I leave for you as an exercise the following improvements :
the split_line routine should not print itself but rather return an array of words - beware you cannot return an automatic array, but it would be another question
you should not have magic constants in you code (120), you should at least have a #define and use symbolic constants, or better accept a line of any size - here again it is not simple because you will have to malloc and free at appropriate places, and again would be a different question
Anyway good luck in learning that good old C :-)
This line does not seems right to me
param[j] = buffer;
because you keep assigning the same value buffer to different param[j] s .
I would suggest you copy all the char s from line[120] to buffer[120], then point param[j] to location of buffer + Next_Word_Postition.
You may want to look at strtok in string.h. It sounds like this is what you are looking for, as it will separate words/tokens based on the delimiter you choose. To separate by spaces, simply use:
dest = strtok(src, " ");
Where src is the source string and dest is the destination for the first token on the source string. Looping through until dest == NULL will give you all of the separated words, and all you have to do is change dest each time based on your pointer array. It is also nice to note that passing NULL for the src argument will continue parsing from where strtok left off, so after an initial strtok outside of your loop, just use src = NULL inside. I hope that helps. Good luck!

Resources