string::substr tutorial needs range added

This is an example from a tutorial for string::substr. Please change it so that the definition of 'pos' is now "but" plus 2 words before it and 2 words after it. Issues needing to be resolved: syntax for 'pos' as a range, seeking words rather than characters, returning words rather than index positions.

// string::substr
#include <iostream>
#include <string>

int main ()
{
std::string str="We think in generalities, but we live in details.";
// (quoting Alfred N. Whitehead)

std::size_t pos = str.find("but"); // position of "but" in str

std::string str3 = str.substr (pos); // get from "but" to the end

std::cout << str3 << '\n';

return 0;
}
Last edited on
Using the standard regular expressions library:

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
#include <iostream>
#include <string>
#include <regex>
#include <iomanip>

int main()
{
    const std::string str = "We think in generalities, but we live in details.";
    
    // try to locate the word 'but' plus 2 words before it and 2 words after it. 

    // regex: any two words, the specific word 'but' ignoring case, any two words
    // note: \w+ - one or more alphanumeric characters
    //       \W+ - one or more non-alphanumeric characters
    //       {2} - repeated exactly two times
    // https://en.cppreference.com/w/cpp/regex/basic_regex
    const std::regex re( "(?:\\w+\\W+){2}but(?:\\W+\\w+){2}", std::regex::icase ) ;

    std::smatch match ; // https://en.cppreference.com/w/cpp/regex/match_results

    // https://en.cppreference.com/w/cpp/regex/regex_search
    if( std::regex_search( str, match, re ) ) // if the regex was found
    {
        std::cout << "string: " << str << '\n'
                  << "        " << std::string( match.prefix().length(), ' ' )
                  << std::string( match.length(), '^' ) << "\n\n"

                  << "prefix: " << std::quoted( match.prefix().str() ) << '\n'
                  << " match: " << std::quoted( match[0].str() ) << '\n'
                  << "suffix: " << std::quoted( match.suffix().str() ) << '\n' ;
    }
    else std::cout << "no match was found\n" ;
}

http://coliru.stacked-crooked.com/a/fe2a23fec22965fb
https://rextester.com/KXIIX71149
Thanks for the fast reply. I didn't know this was venturing so far off topic into regex. I ran it in the console and did a 5 minute refactor to assign the range to a new variable. Thanks again:

#include <iostream>
#include <string>
#include <regex>
#include <iomanip>

int main()
{
const std::string str = "We think in generalities, but we live in details.";
const std::regex re("(?:\\w+\\W+){2}but(?:\\W+\\w+){2}", std::regex::icase);

std::smatch match;
if (std::regex_search(str, match, re))
{
std::string range1 = match[0].str();
std::cout << range1 << '\n';
}
else
std::cout << "no match was found\n";
}
This can't match @JLBorges', which is superbly efficient. However, here's a try without regex. Would require more code to make it case-independent.

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
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int main()
{
   string str = "We think in generalities, but we live in details.";
   string match = "but";
   int numWords = 2;
   
   int pos = str.find( " " + match + " " );                // needs to match case at the moment

   if ( pos != string::npos ) 
   {
      int p = pos, q = pos + match.size() + 1;             // allow for at least one space either side to delimit word
      for ( int w = 1; w <= numWords; w++ )
      {
         while( p >= 0 &&  isspace( str[p] ) ) p--;
         while( p >= 0 && !isspace( str[p] ) ) p--;
      }
      p++;                                                 // p ends as position of first character
      for ( int w = 1; w <= numWords; w++ )
      {
         while ( q < str.size() &&  isspace( str[q] ) ) q++;
         while ( q < str.size() && !isspace( str[q] ) ) q++;
      }                                                    // q ends as ONE AFTER last character

      cout << str.substr( p, q - p ) << '\n';  
   }
}


in generalities, but we live
Last edited on
Topic archived. No new replies allowed.