C-String question

Hey again,
I'm working on a program that is asking me to take 3 strings(str1,str2,str3) and replace str3 with str2 in str1.Which functions of C-strings can I use to make this happen? I know with C++ strings I could just use the replace function.

str1=the dog jumped over the fence
str2=the
str3=that
Last edited on
I think you said it wrong. replace string 3, that, with str2, the, in str1 (does not contain).

There is no easy way. Its going to be hands on and its going to depend on how str1 is defined.
lets kill the first the and assume you want to replace the with that.

dog jumped over the fence
becomes
dog jumped over that fence

lets see what we can do … give me a few min, but you are going to need at least
-strstr
-memcpy
-strlen

Here is an incomplete starting example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

int main()
{
char str1[100] = "dog jumped over the fence"; //the way I made this string is important.... I gave lots of extra room, and it can be edited. 
char str2[] = "the";
char str3[] = "that";
int offset = strlen(str3)-strlen(str2); //how much do we need to shift the string?
char * ss;
ss = strstr(str1, str2); //is the target even in there, and if so, you need to loop 
//to do it until it is no longer there (assuming the replace != the original too, 
//may need to check that)
if(ss)  //found it. c++ borked this.  null = 0 = false.  strstr rocks ;) 
{
if(offset >0)  //you need more cases, what if this is 0, what if is negative?
//but if its positive shift the data to make room for the extra letters
  memmove(ss+strlen(str2)+offset, ss+strlen(str2), strlen(str1)); 
//the strlen str1 is me being lazy you can find the exact amount if you want. 
  memcpy(ss,str3, strlen(str3));
  }
  cout << str1 << endl;
}


**memmove is able to do memcpy inside the same buffer, memcpy may not do this safely, I bugged that up the first time.

here is a C program to do it
https://www.geeksforgeeks.org/c-program-replace-word-text-another-given-word/
but honestly I think it may be a little overdone due to using dynamic memory for some unholy reason.
hands-on C string stuff takes getting used to. Let us know if you need more, but that should get you a long way towards getting it done.
Last edited on
I've manipulated what you suggested. Here's what I've produced, can you assist me in the ouput?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Replaces the SubString
void RSS(char* str1, char* str2, char* str3)
{
    char* ss;
    int offset = strlen(str3)-strlen(str2);
    int cnt;
    for(cnt=0; (ss=strstr(str1,str2)); ++cnt)
    {
        if(!ss)
        break;
        ss++;

    if(ss)
    {
        if(offset > 0)
        memmove(ss+strlen(str2)+offset, ss+strlen(str2), strlen(str1));
        strncpy(ss,str3,strlen(str3));

    }}
    out << "The new String 1: " << str1 << endl;
}

OUTPUT
 
The new String 1: tthatdog jumped over tthatfence
Are there any C++ functions that can check for upper/lower case and or if a digit is present? Somewhat like the C-String function of isdigit, islower, isupper.
Somewhat like the C-String function of isdigit, islower, isupper.

Actually isdigit, islower, etc are ctype functions that deal with single characters, not C-strings. Those functions are also part of C++.

This seems to work. Minor change or two.
You still need to deal with offset ==0 and offset < 0 cases.
You almost had it, but that break logic was all messed up and I honesty have NO clue why you ++ss … should that have been count?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iomanip>
#include <iostream>
#include <cmath>
#include <cstring>

using namespace std;
//Replaces the SubString
void RSS(char* str1, char* str2, char* str3)
{
    char* ss = str1;	
    int offset = strlen(str3)-strlen(str2);
    int cnt = 0;
    
	while(ss)
    {
		ss=strstr(str1,str2);       

    if(ss)
		{
			if(offset > 0)			
			memmove(ss+strlen(str2)+offset, ss+strlen(str2), strlen(str1));	    
			strncpy(ss,str3,strlen(str3));	
			cnt++;
		}
    }
    cout << "The new String 1: " << str1 << endl;
}

int main()
{ 

char str1[100] = "the dog jumped over the fence"; 
char str2[] = "the";
char str3[] = "that";
RSS (str1,str2,str3);

}



The new String 1: that dog jumped over that fence

whole mess is an exercise in why c++ strings are a real improvement most of the time.
Last edited on
I have a few more issues. The issues I am having are:
I need to figure out how to replace the word "Sid" without affecting the word "Sidney"
PW is printing the "error" I have even when the PW is sufficient.
DATA for Substring
1
2
3
4
5
/*Sid likes to eat nuts but the brother, Sidney likes to eat fruit. One time Sid put a pecan in 
Sidney's banana and boy hidey did Sid get a chuckle out of 
Sidney's misfortune.*/ //String 1
Sid//string 2
Mikey//string 3 

1
2
3
4
5
6
7
8
9
10
11
12
void ReplaceCPPString(string str1,string str2,string str3)
{
    int ss=0;
    while((ss = str1.find(str2,ss)) != string :: npos)
    {
        ss=str1.find(str2,ss);
        str1.replace(ss, str2.size(), str3);
        ss += str3.size();
    }

    out << "The New String 1: " << str1 << endl;
}

MAIN FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Fourth Problem
void ReplaceSubString2()
{
    ifstream inf4("ReplaceSubstring2.in");
    if(!inf4)
        out << "ERROR Opening ReplaceSubstring2.in";

    string input4a, input4b, input4c;//string variables for data

    getline(inf4,input4a);//retrieves the data
    input4a.insert(74,1,'\n');//inserts a new line
    getline(inf4,input4b);
    getline(inf4,input4c);

    out << "\n\t\t\tReplace Substring #4(Class String)"
        << "\nString 1: " << input4a
        << "\nString 2: " << input4b
        << "\nString 3: " << input4c << endl;

    ReplaceCPPString(input4a, input4b, input4c);

    inf4.close();
}

AND I have another C++ String attempt at reading in PW data and enuring it has the proper criteria.

LENGTH
1
2
3
4
5
6
7
/Checks PW /length C++ Strings
void LengthCheck(string input)
{
    if(input.length() < 6)//Using C++ Strings, checks length of pw
        out << "**ERROR** PASSWORD must be at least"
            << " 6 characters in length\n";
}

UPPER/LOWER
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Checks PW for Upper and Lower Case C++ Strings
void UpperLowerCheck(string input)
{
    bool cntup=0, cntdwn=0;
    for(int cnt=0;cnt<input.length(); cnt++)
    {
        if(isupper(input.length()))
            cntup=1;
        if(islower(input.length()))
            cntdwn=1;
    }
    if(cntup<1 || cntdwn<1)
        out << "**ERROR** PASSWORD must contain"
            << " one Upper and Lower case letter\n";
}

DIGIT
1
2
3
4
5
6
7
8
9
10
11
12
/Checks PW for digit C++ String
void DigitCheck(string input)
{
    bool digit=0;
    for(int cnt=0; cnt < input.length(); cnt++)
    {
        if(isdigit(input.length()))
            digit=1;
    }
    if(digit<1)
        out << "**ERROR** PASSWORD must contain one digit.\n";
}


MAIN FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Sixth Problem
void PasswordVerifier2()
{
    ifstream inf6("PwVerifier.in");
    if(!inf6)
        out << "Error Opening PwVerifier.in";

    string pw;

    out << "\n\t\t\tPassword Verifier #6(Class String)";

    for(int i = 0; i < 7; i++)
    {
       inf6 >> pw;
       out << "\nPassword: " << pw << endl;
       LengthCheck(pw);
       UpperLowerCheck(pw);
       DigitCheck(pw);
    }
    inf6.close();
}

DATA
1
2
3
4
5
6
7
ABC123
TwoFor1
Sid22
howdyYALL
Seventy8
GorillaalliroG
ThisIs4You
Last edited on
You might try something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

bool is_word(const string& str, const string& find, size_t pos)
{
    size_t end = pos + find.size();
    return (pos == 0 || !isalpha(str[pos - 1]))
        && (end == str.size() || !isalpha(str[end]));
}

void ReplaceCPPString(string& str, const string& find, const string& replace)
{
    for (size_t pos{}; (pos = str.find(find, pos)) < str.size(); )
    {
        if (is_word(str, find, pos))
        {
            str.replace(pos, find.size(), replace);
            pos += replace.size();
        }
        else
            pos += find.size();
    }
}

int main()
{
    string s{"Sid likes to eat nuts but the brother, Sidney likes to eat "
             "fruit. One time Sid put a pecan in Sidney's banana and boy "
             "hidey did Sid get a chuckle out of Sidney's misfortune."};

    ReplaceCPPString(s, "Sid", "Mikey");

    cout << "New string: " << s << '\n';
}

Last edited on
its yet another 'you can't use strings' class dutch.

You can do it by looking at the next character after the chunk you care about. If it is a in {a-z} or {A-Z} then its not a match, do not replace, else replace it.
Eg Sidney .. n is next letter, do not replace.
Sid ... space is next letter, replace
Sid. ... . is next letter, replace.
and so on.



@jonnin, what do you mean by 'can't use strings' class'? For this replace substring its expected to use string instead of char.

@dutch, thank you for the solution, i don't quite understand it all but it works like a charm.

I figured out the pw issue, I was using input.length() when I needed to use input.at(i);
@jonnin, what do you mean by 'can't use strings' class'? For this replace substring its expected to use string instead of char.

you said: I know with C++ strings I could just use the replace function.
And said or implied heavily that you needed a C solution.
If you wanted C++ strings, its trivial. If you are going to do that, why did you have me doing all that C mess??
Last edited on
Jonnin, part of the assignment is in C while some of the assignment is C++.
Topic archived. No new replies allowed.