How to find substring from string? - c++

How do I find a substring from the string path "/user/desktop/abc/post/" using C/C++? I want to check if folder "abc" is present or not in that path.
Path is character pointer char *ptr = "/user/desktop/abc/post/";

Use std::string and find.
std::string str = "/user/desktop/abc/post/";
bool exists = str.find("/abc/") != std::string::npos;

In C, use the strstr() standard library function:
const char *str = "/user/desktop/abc/post/";
const int exists = strstr(str, "/abc/") != NULL;
Take care to not accidentally find a too-short substring (this is what the starting and ending slashes are for).

Example using std::string find method:
#include <iostream>
#include <string>
int main (){
std::string str ("There are two needles in this haystack with needles.");
std::string str2 ("needle");
size_t found = str.find(str2);
if(found!=std::string::npos){
std::cout << "first 'needle' found at: " << found << '\n';
}
return 0;
}
Result:
first 'needle' found at: 14.

Use strstr(const char *s , const char *t)
and include<string.h>
You can write your own function which behaves same as strstr and you can modify according to your requirement also
char * str_str(const char *s, const char *t)
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++)
{
for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++);
if (k > 0 && t[k] == '\0')
return (&s[i]);
}
return NULL;
}

As user1511510 has identified, there's an unusual case when abc is at the end of the file name. We need to look for either /abc/ or /abc followed by a string-terminator '\0'. A naive way to do this would be to check if either /abc/ or /abc\0 are substrings:
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "/user/desktop/abc";
const int exists = strstr(str, "/abc/") || strstr(str, "/abc\0");
printf("%d\n",exists);
return 0;
}
but exists will be 1 even if abc is not followed by a null-terminator. This is because the string literal "/abc\0" is equivalent to "/abc". A better approach is to test if /abc is a substring, and then see if the character after this substring (indexed using the pointer returned by strstr()) is either a / or a '\0':
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "/user/desktop/abc", *substr;
const int exists = (substr = strstr(str, "/abc")) && (substr[4] == '\0' || substr[4] == '/');
printf("%d\n",exists);
return 0;
}
This should work in all cases.

If you are utilizing arrays too much then you should include cstring.h because it has too many functions including finding substrings.

Related

C++ code doesn't compile because of an error

I'm currently solving problems for my high school final exam at programming in C++. I tried solving a problem in CodeBlocks, but it gives me this error at line 13:
error: invalid conversion from 'const char*' to 'int' [-fpermissive]
I don't see what is wrong.
The problem is about removing the last consonant from a string. The string is "mare frig saci" and it should produce "mare frig sai", removing the last 'c'.
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[256];
int i;
cin.get(s,256);
for(i=strlen(s)-1;i=0;i--)
{
if(strchr(s,"aeiou")!=0)
strcpy(s+i+1,s+i-1);
}
cout<<s;
return 0;
}
There are a few problems:
i=0 is not a condition, it's an assignment. i>=0 is probably what you're looking for here
strchr take in a string and char (1), and return a pointer (2), not an int to be compared. Both (1) and (2) condition isn't sastified. In any case, strchr is not ideal to use here.
I recommended using std::string (as it's more easy to use and standard in C++) and std::string::find_last_of, which find the last character in string inside a set of characters, exactly what you wanted here:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s; getline(std::cin, s);
string cons = "bcdfghjklmnpqrstvwxyz";
size_t pos = s.find_last_of(cons);
if (pos != string::npos) //if a consonant is found
{
s.erase(pos, 1);
}
cout << s;
}
std::strchr - The valid signatures are
const char* strchr( const char* str, int ch );
char* strchr( char* str, int ch );
So, you are supplying it with the wrong things.
std::strcpy - "The behavior is undefined if the strings overlap" - so you can't use std::strcpy to move the end of the string to the new place. Instead use std::memmove.
Since the string you mention contains a space at the end, you must add space to the list of vowels.
You assign 0 to i instead of checking it's value.
Example:
#include <cstring>
#include <iostream>
int main() {
char s[256] = " mare frig saci ";
for (size_t len = strlen(s), i = len; i-- > 0;) { // corrected loop
if (std::strchr("aeiou ", s[i]) == nullptr) { // corrected check
std::memmove(s + i, s + i + 1, len - i); // corrected move
break; // and break out
}
}
std::cout << s << '\n';
}

Find occurrences of all substrings in a given string

I use a simple string function strstr to find the first occurrence of a string in some text. I used the following code to count the number of unique words in a text.
for (int i = 0; i < 24; i++)
{
if (strstr(text, ops[i]))
{
op++;
}
}
But I want to find the occurrence of all the sub strings in the program. How can I do this?
strstr() is for the C-style string, if you are really using C++, std::string and its member function would be much more convenient.
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s("hello hello");
int count = 0;
size_t nPos = s.find("hello", 0); // first occurrence
while(nPos != string::npos)
{
count++;
nPos = s.find("hello", nPos + 1);
}
cout << count;
};
You can use one of the std::string find methods which would be easier (and safer), but if you really need to use strstr:
int _tmain(int argc, _TCHAR* argv[])
{
const char test[] = "this test is a test";
const char subStr[] = "test";
const char* pCurrent = strstr( test, subStr );
while( pCurrent != NULL )
{
std::cout << "found" << std::endl;
pCurrent++;
pCurrent = strstr( pCurrent, subStr );
}
return 0;
}
This just increments the point where the last sub string was found. Note that you should do the normal string length, NULL and safety checks.

Splitting a string into multiple strings with multiple delimiters without removing?

I use boost framework, so it could be helpful, but I haven't found a necessary function.
For usual fast splitting I can use:
string str = ...;
vector<string> strs;
boost::split(strs, str, boost::is_any_of("mM"));
but it removes m and M characters.
I also can't siply use regexp because it searches the string for the longest value which meets a defined pattern.
P.S. There are a lot of similar questions, but they describe this implementation in other programming languages only.
Untested, but rather than using vector<string>, you could try a vector<boost::iterator_range<std::string::iterator>> (so you get a pair of iterators to the main string for each token. Then iterate from (start of range -1 [as long as start of range is not begin() of main string], to end of range)
EDIT: Here is an example:
#include <iostream>
#include <string>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/range/iterator_range.hpp>
int main(void)
{
std::string str = "FooMBarMSFM";
std::vector<boost::iterator_range<std::string::iterator>> tokens;
boost::split(tokens, str, boost::is_any_of("mM"));
for(auto r : tokens)
{
std::string b(r.begin(), r.end());
std::cout << b << std::endl;
if (r.begin() != str.begin())
{
std::string bm(std::prev(r.begin()), r.end());
std::cout << "With token: [" << bm << "]" << std::endl;
}
}
}
Your need is beyond the conception of split. If you want to keep 'm or M', you could write a special split by strstr, strchr,strtok or find function. You could change some code to produce a flexible split function.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void split(char *src, const char *separator, char **dest, int *num)
{
char *pNext;
int count = 0;
if (src == NULL || strlen(src) == 0) return;
if (separator == NULL || strlen(separator) == 0) return;
pNext = strtok(src,separator);
while(pNext != NULL)
{
*dest++ = pNext;
++count;
pNext = strtok(NULL,separator);
}
*num = count;
}
Besides, you could try boost::regex.
My current solution is the following (but it is not universal and looks like too complex).
I choose one character which couldn't appear in this string. In my case it is '|'.
string str = ...;
vector<string> strs;
boost::split(strs, str, boost::is_any_of("m"));
str = boost::join(strs, "|m");
boost::split(strs, str, boost::is_any_of("M"));
str = boost::join(strs, "|M");
if (boost::iequals(str.substr(0, 1), "|") {
str = str.substr(1);
}
boost::split(strs, str, boost::is_any_of("|"));
I add "|" before each of symbols m/M, except of the very first position in string. Then I split the string into substrings with deleting of this extra character

Finding adjacent chars in a string

How to find two adjacent characters in a string? My search for adjacent characters should only consider a set of characters defined by me.
I solved my problem using this function:
unsigned checkField (myset string, char mychar)
{
unsigned counter;
for (counter = 0; counter <= myset.length () - 1; counter + +)
if (myset [counter] == mychar)
return 1;
return 0; / * NOT FOUND * /
}
It may be useful to someone in the future
If it's ok to use boost, and you don't need the ultimate in efficiency, then the easiest way may be to use a regular expression such as "([abcd])\\1". For details on matching strings with boost regexps, see the boost regex docs.
I imagine you are storing each part of your equation separately at some point? Eg. "55" "+" "hh" "+" "bc" ?
In this case would it not just be enough to check that the sizeof is 1, and send an error if not? Sorry if I am missing something! Otherwise regular expressions as Edward suggested (+1) seem most appropriate.
Edit: also, of course it would be easy to check that the chars are/are not the ones you specified at the top.
Some quick code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
const char* find_adjacent_string(const char* str, const char* set)
{
const char* loc = NULL;
if(set != NULL)
{
int size = strlen(set);
char adj[3];
adj[2] = '\0';
for(int i = 0; i + 1 < size; i++)
{
adj[0] = set[i];
adj[1] = set[i + 1];
loc = strstr(str, adj);
if(loc != NULL)
{
break;
}
}
}
return loc;
}
int main()
{
const char* myset = "pl";
const char* mystr = "apple";
printf("found at %i\n", find_adjacent_string(mystr, myset) - mystr);
return 0;
}

Reversing a string, weird output c++

Okay, so I'm trying to reverse a C style string in C++ , and I'm coming upon some weird output. Perhaps someone can shed some light?
Here is my code:
int main(){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-1;
int i =0;
while (&str+n >= &str){
str2[i] = *(str+n);
n--;
i++;
}
int str2size = sizeof(str)/sizeof(char);
int x;
for(x=0;x<str2size;x++){
cout << str2[x];
}
}
The basic idea here is just making a pointer point to the end of the string, and then reading it in backwards into a new array using pointer arithmetic.
In this particular case, I get an output of: " gnirts"
There is an annoying space at the beginning of any output which I'm assuming is the null character? But when I try to get rid of it by decrementing the strSize variable to exclude it, I end up with some other character on the opposite end of the string probably from another memory block.
Any ideas on how to avoid this? PS: (would you guys consider this a good idea of reversing a string?)
A valid string should be terminated by a null character. So you need to keep the null character in its original position (at the end of the string) and only reverse the non-null characters. So you would have something like this:
str2[strSize - 1] = str[strSize - 1]; // Copy the null at the end of the string
int n = strSize - 2; // Start from the penultimate character
There is an algorithm in the Standard Library to reverse a sequence. Why reinvent the wheel?
#include <algorithm>
#include <cstring>
#include <iostream>
int main()
{
char str[] = "string";
std::reverse(str, str + strlen(str)); // use the Standard Library
std::cout << str << '\n';
}
#ildjarn and #Blastfurnace have already given good ideas, but I think I'd take it a step further and use the iterators to construct the reversed string:
std::string input("string");
std::string reversed(input.rbegin(), input.rend());
std::cout << reversed;
I would let the C++ standard library do more of the work...
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
typedef std::reverse_iterator<char const*> riter_t;
char const str[] = "string";
std::size_t const strSize = sizeof(str);
char str2[strSize] = { };
std::copy(riter_t(str + strSize - 1), riter_t(str), str2);
std::cout << str2 << '\n';
}
while (&str+n >= &str){
This is nonsense, you want simply
while (n >= 0) {
and
str2[i] = *(str+n);
should be the much more readable
str2[i] = str[n];
Your while loop condition (&str+n >= &str) is equivalent to (n >= 0).
Your *(str+n) is equivalent to str[n] and I prefer the latter.
As HappyPixel said, your should start n at strSize-2, so the first character copied will be the last actual character of str, not the null termination character of str.
Then after you have copied all the regular characters in the loop, you need to add a null termination character at the end of the str2 using str2[strSize-1] = 0;.
Here is fixed, working code that outputs "gnirts":
#include <iostream>
using namespace std;
int main(int argc, char **argv){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-2; // Start at last non-null character
int i = 0;
while (n >= 0){
str2[i] = str[n];
n--;
i++;
}
str2[strSize-1] = 0; // Add the null terminator.
int str2size = sizeof(str)/sizeof(char);
int x;
cout << str2;
}