Custom substring class help. Comparing elements of two substrinsg

I'm working within the equals_to function. I'm trying to figure out how to compare the elements using a subscript, but I can't do something like other[pos]. Any hints are greatly appreciated.

substring.cpp
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include "substring.h"
#include <string>
#include <iostream>

// Constructor that takes a reference to a string:
substring::substring( std::string& str )
    :
    m_str(str),
    m_begin(0),
    m_end(str.length())
{
    /*
    The substring class is entirely dependent on the std::string object
    which has to be passed to each constructor. It will be refferred to
    as "underlying string object" in our comments.

    DONE: Add initializer list to this constructor, or your code won't
    compile.

    DONE: Add two member variables to accommodate the substring
    positions,

        size_t m_begin;  // absolute offset of the substring beginning
        size_t m_end;    // absolute offset of the substring ending

    and set these positions to match the entire string.
    */
}

// Constructor that takes string reference, beginning, and ending positions
substring::substring( std::string& str, size_t pos_begin, size_t pos_end )
    :
    m_str(str),
    m_begin(pos_begin),
    m_end(pos_end)
{
    /*
    In addition to std::string object, this constructor
    takes two absolute positions to initialize m_begin
    and m_end offsets of the substring object.

    DONE: Add initializer list to this constructor, or your code won't
    compile.
    */
}

// Return copy of the substring as std::string object
std::string substring::str() const
{
    /*
    This function returns a copy of the string object, initialized
    by the characters of the substring.

    DONE: modify the following statement to construct and return
    the appropriate string:
    */
    return m_str.substr(m_begin, size());
    //                  starting length
    //                  position
}

// Return substring size
size_t substring::size() const
{
    return m_end - m_begin;
}

// Return beginning position
size_t substring::begin() const
{
    return m_begin;
}

// Return ending position
size_t substring::end() const
{
    return m_end;
}

// Set beginning position
void substring::begin( size_t pos )
{
    m_begin = pos;
}

// Set ending position
void substring::end( size_t pos )
{
    m_end = pos;
}

// The string content is set to an empty string
void substring::clear()
{
    m_str.replace(m_begin, size(), "");
    m_end = m_begin;
}

// Replace substring with str
substring& substring::replace( std::string const& str )
{
    m_str.replace(m_begin, size(), str);
    m_end = m_begin + str.length();
    return *this;
}

// Fill substring with a particular character
substring& substring::fill( char ch )
{
        size_t pos = m_begin;
        for(; pos < m_end; ++pos){
             m_str[pos] = ch;
        }
    return *this;
}

// Insert str at the specified position:
substring& substring::insert( std::string const& str, size_t pos )
{
    /*
    Hint: use insert() member function of std::string.

    TODO: because insert causes changes in the underlying substring,
    the function must compare its beginning and ending against the
    insertion position and the length of the string being inserted.
    The substring needs to adjust its beginning and ending positions
    as demonstrated by the following diagrams:

    Example 1.
      BEFORE insert:

        insert( "abc", pos )
                        |
                     .--'
                     |
            m_str: XXXX?????????????????XXXXXXXXXX
                       |                |
                       '-m_begin        `-m_end

      AFTER insert:
                     |
            m_str: XXabcXX?????????????????XXXXXXXXXX
                          |                |
                          '-m_begin:       `-m_end:
                            got adjusted     got adjusted

    Example 2.
      BEFORE insert:

        insert( "abc", pos )
                        |
                        `-------.
                                |
            m_str: XXXX?????????????????XXXXXXXXXX
                       |                |
                       '-m_begin        `-m_end

      AFTER insert:
                                |
            m_str: XXXX?????????abc???????XXXXXXXXXX
                       |                  |
                       '-m_begin          `-m_end: got adjusted


    IMPORTANT: Make your own decision regarding two special cases
    when the insertion occurs exactly at the beginning, or exactly
    at the ending of the substring. Make sure to document your
    coding in the comments of your program.
    */
    std::cout << "end pos: " << m_end << '\n';//debug
    std::cout << "beg pos: " << m_begin << '\n';//debug

    m_str.insert(pos, str);

    if (pos < m_begin){
        m_begin += str.length();
        m_end += str.length();
        std::cout << "pos < m_begin \n";//db
    }
    else if (pos > m_begin && pos < m_end){
        m_end += str.length();
        std::cout << "pos > m_begin AND  < m_end \n";//db
    }
    else if (pos == m_begin){
        m_end += str.length();
        //assuming the user wants the inserted string to be the beginning
        std::cout << "pos == m_begin \n";//db
    }
    else if (pos == m_end){
        //assuming the user wants the inserted string to be the end
        m_end += str.length();
        std::cout << "pos == m_end \n";//db
    }

    std::cout << "end pos: " << m_end << '\n';//debug
    std::cout << "beg pos: " << m_begin << '\n';//debug

    return *this;
}

// Convert substring to UPPER CASE
substring& substring::toupper()
{
    size_t pos = m_begin;
        for(; pos < m_end; ++pos){
             m_str[pos] = std::toupper(m_str[pos]);
        }
    return *this;
}

// Convert substring to lower case
substring& substring::tolower()
{
    size_t pos = m_begin;
        for(; pos < m_end; ++pos){
             m_str[pos] = std::tolower(m_str[pos]);
        }
    return *this;
}

// Search for a new substring starting at the specified position:
size_t substring::search( const std::string& str, size_t pos )
{
    /*
    DONE: use find() of the underlying string and update the beginning
    and the ending positions of the substring.

    DONE: when find() call fails, it returns back the member value
    std::string::npos. In such case the substring must not update
    its positions and also return std::string::npos back to the caller:
    */
    size_t result = result = m_str.find(str, pos);
    if (result != std::string::npos){
        m_begin = result;
        m_end = m_begin + str.length();
        return result;
    }
    else{
        return std::string::npos;
    }
}

// The string content is set to the size of entire string
void substring::expand()
{
    /*
    DONE: Update substring positions to match the entire
    underlying string.
    */
    m_begin = 0;
    m_end = m_str.length();
}

// Equality test between two substrings
bool substring::equals_to( substring const& other ) const
{
    /*
    TODO: Compare this substring with another character by character.
    The test should succeed if every character in both substrings
    matches exactly.

    Return true, if the underlying text fragments are the same.
    Return false otherwise.
    */
    size_t pos = m_begin;

    return false;
}

substring.h
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// CIS-62 substring class

#ifndef _CIS62_SUBSTRING_H_INCLUDED_
#define _CIS62_SUBSTRING_H_INCLUDED_

#include <string>

class substring {
    std::string& m_str;
    size_t m_begin;  // absolute offset of the substring beginning
    size_t m_end;    // absolute offset of the substring ending
public:
    // Constructor that takes a reference to a string:
    substring( std::string& str );

    // Constructor that takes string reference, beginning, and ending positions
    substring( std::string& str, size_t pos_begin, size_t pos_end );

    // Return copy of the substring as std::string object
    std::string str() const;

    // Return substring size
    size_t size() const;

    // Return beginning position
    size_t begin() const;

    // Return ending position
    size_t end() const;

    // Set beginning position
    void begin( size_t pos );

    // Set ending position
    void end( size_t pos );

    // The string content is set to an empty string
    void clear();

    // Replace substring with str
    substring& replace( std::string const& str );

    // Fill substring with a particular character
    substring& fill( char ch );

    // Insert str at the specified position:
    substring& insert( std::string const& str, size_t pos );

    // Convert substring to UPPER CASE
    substring& toupper();

    // Convert substring to lower case
    substring& tolower();

    // Search for a new substring starting at the specified position:
    size_t search( const std::string& str, size_t pos );

    // The string content is set to the size of entire string
    void expand();

    // Equality test between two substrings
    bool equals_to( substring const& other ) const;

    // Equality test between substring and std::string
    bool equals_to( std::string const& str ) const;

    // Merge with another substring
    substring& merge( substring const& other );

    // Swap with another substring
    void swap( substring& other );

    // Prepare substring for parsing
    substring& parse();

    // Test if substring is alphabetic
    substring& isalpha();

    // Test if substring is upper case
    substring& isupper();

    // Test if substring is lower case
    substring& islower();

    // Test if substring is digit
    substring& isdigit();

    // Test if substring is alphabetic or digit
    substring& isalnum();

    // Test if substring is blank, tab, newline, return, formfeed, or vertical tab
    substring& isspace();

    // Test if substring is matches text specified by str
    substring& isstr( const std::string& str );

    // Test if substring is empty
    substring& isempty();

    // Return beginning position
    bool succeeded() const;

    // Return matching substring
    substring match() const;

    // Undo changes caused by parsing
    substring& unparse();
};

#endif // _CIS62_SUBSTRING_H_INCLUDED_ 

substring_main.cpp
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// main driver sample to test substring functionality.

#include <cassert>
#include <iostream>
#include "substring.h"

int main()
{
    //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    // Test basic substring functionality
    //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    std::string str( "abc" );
    substring sub( str );

    std::cout << '\n' << sub.str() << '\n';//DEBUG

    assert( sub.str() == "abc" );
    assert( sub.begin() == 0 );
    assert( sub.end() == 3 );
    assert( sub.end() == sub.size() );

    sub.begin( 1 ); // reposition absolute offsets
    sub.end( 2 );
    assert( sub.str() == "b" );

    std::cout << '\n' << sub.str() << '\n';//DEBUG

    sub.replace( "HELLO" );
    assert( sub.str() == "HELLO" );
    assert( str == "aHELLOc" );
    assert( sub.begin() == 1 );
    assert( sub.end() == 6 );
    assert( sub.size() == 5 );

    sub.clear();
    assert( sub.str() == "" );
    assert( str == "ac" );
    assert( sub.begin() == 1 );
    assert( sub.end() == 1 );
    assert( sub.size() == 0 );

    sub.insert( "XYZ", sub.begin() );
    assert( str == "aXYZc" );

    sub.expand();
    assert( str == "aXYZc" );
    assert( sub.begin() == 0 );
    assert( sub.end() == str.size() );

    size_t result = sub.search( "YZc", sub.end() );
    assert( result == std::string::npos );

    result = sub.search( "YZc", sub.begin() );
    assert( result == 2 );
    assert( sub.begin() == 2 );
    assert( sub.end() == str.size() );
    assert( sub.size() == 3 );

    sub.fill( '?' );
    assert( sub.begin() == 2 );
    assert( sub.end() == str.size() );
    assert( sub.equals_to( "???" ) );
    assert( str == "aX???" );

    sub.expand();
    sub.toupper();
    assert( sub.equals_to( "AX???" ) );
    assert( str == "AX???" );

    sub.tolower();
    assert( sub.equals_to( "ax???" ) );
    assert( str == "ax???" );

    substring sub2 = sub; // invokes copy constructor
    result = sub2.search( "x?", sub.begin() );
    assert( sub2.equals_to( "x?" ) );
    assert( sub.equals_to( "ax???" ) );

    sub2.merge( sub );
    assert( sub2.equals_to( "ax???" ) );
    assert( sub.equals_to( sub2 ) );

    //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    // Parsing tests
    //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    str = "ABC123abc ";
    sub.expand();
    if ( sub.parse().isalpha().isdigit().isalnum().isspace().isempty().succeeded() ) {
        sub.match().replace( "xyz" );
        assert( str == "xyz" );
    } else {
        sub.unparse(); // restore the original substring
    }

    return 0;
}
You can use std::string::compare to compare parts of strings.

Another way is to first check if both substrings are of the same length and return false if they are not. If they have the same length you just use a loop and check each character and return false if you find a mismatch. After the loop you return true because then you know the strings are equal.
Can someone tell me where I'm going wrong here?

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
bool substring::equals_to( substring const& other ) const
{
    /*
    TODO: Compare this substring with another character by character.
    The test should succeed if every character in both substrings
    matches exactly.

    Return true, if the underlying text fragments are the same.
    Return false otherwise.
    */
    size_t pos = m_begin;
    size_t end = pos + other.m_str.length();

    if (m_str.length() == other.m_str.length()){
        std::cout << "Equal Lengths";
        for (; pos < m_end; pos++){
            if (m_str[pos] != other.m_str[pos]){
                return false;
            }
            if (m_str[pos] == other.m_str[pos]){
                if (pos == end){
                    return true;
                }
            }
        }
    }
    else{
        return false;
    }
    
    //return false;
}
Last edited on
It's not the length of the string you are interested in. It's the length of the substring.
Updated, but still not working.

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
// Equality test between two substrings
bool substring::equals_to( substring const& other ) const
{
    /*
    TODO: Compare this substring with another character by character.
    The test should succeed if every character in both substrings
    matches exactly.

    Return true, if the underlying text fragments are the same.
    Return false otherwise.
    */
    size_t pos = m_begin;
    size_t end = pos + other.m_str.length();
    size_t length = m_str.length() - m_begin;
    
    if (length == other.m_str.length()){
        std::cout << "Equal Lengths";
        for (; pos < m_end; pos++){
            if (m_str[pos] != other.m_str[pos]){
                return false;
            }
            if (m_str[pos] == other.m_str[pos]){
                if (pos == end){
                    return true;
                }
            }
        }
    }
    else{
        return false;
    }
}
Last edited on
You can't use pos to index both strings because they might have different m_begin.

substring has a member function called size() that gives you the length of the substring. Use it!

Last edited on
... still

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
// Equality test between two substrings
bool substring::equals_to( substring const& other ) const
{
    /*
    TODO: Compare this substring with another character by character.
    The test should succeed if every character in both substrings
    matches exactly.

    Return true, if the underlying text fragments are the same.
    Return false otherwise.
    */
    size_t pos = m_begin;
    size_t i = 0;

    if ( m_str.size() == other.m_str.length()){
        std::cout << "Equal Lengths";
        for (; pos < m_end; pos++){
            if (m_str[pos] != other.m_str[i]){
                return false;
            }
            i++;
            if (m_str[pos] == other.m_str[i] && pos == m_end){
                return true;
            }
        }
    }
    else{
        return false;
    }
}
How do I access the substring? Do I use a this pointer?
C++ comes with a lot of useful functions, in this case, std::equal() fits the bill just right:

1
2
3
4
5
6
7
8
9
10
11
12
13
bool substring::equals_to( std::string const& other ) const
{
    return other.size() == size() &&
           std::equal(other.begin(), other.end(), m_str.begin() + m_begin);
}

bool substring::equals_to( substring const& other ) const
{
    return other.size() == size() &&
           std::equal(m_str.begin() + m_begin,
                      m_str.begin() + m_end,
                      other.m_str.begin() + other.m_begin);
}


By the way, don't forget to fix that " result = result =" in line 232
Last edited on
The assertion on line 62 in main is still failing after I implement your version. Also, I think I'm technically supposed to do this by comparing character by character, as the description says, but I'm going to look up the std::equal() function to better understand what you wrote.
Works for me, with the calls to non-existent functions commented out:

~ $ ./test

abc

b
end pos: 1
beg pos: 1
pos == m_begin 
end pos: 4
beg pos: 1
test: test.cc:80: int main(): Assertion `sub2.equals_to( "ax???" )' failed.


(the last one is after the non-existent merge())
Thanks, but I'm don't feel right just copying your code. I need to do it character by character anyway. Can anyone provide further help with that? Really lost here.
Last edited on
Topic archived. No new replies allowed.