I try with the following code to check if the string contain specific characters, but i want to check if this characters in order way this my code
string string1= "Amed";
string string2= "Anbhsmegfd";
std::string x(string1);
if (x.find_first_not_of(string2) != std::string::npos)
{
std::cerr << "Error\n";
}
in my code check if the string contain characters that give string1 but i want to check if find this character in order way
as an example
string1 ="Amed";
string2= "Aehdkm"
the string1 found in string2
but i need the output will be error because e appear before m
how can i make that ?
Would something like this work for you?
string s1 = "Amed";
string s2 = "Aehkm";
size_t k = 0;
for (size_t i = 0; i < s2.size(); ++i)
if (s1[k] == s2[i]) {
k++;
if (k == s1.size()) {
cout << "found" << endl;
break;
}
}
just write the code.Here is psuedo code, I leave it to you to convert to c++
char* s = str2
foreach (char c in str1)
char *find = indexof(s, c)
if(!find)
error;
s = find
ie - look for the first char - if found move pointer to where you found that char and search for next char, else fail
Related
I have a runtime problem with code below.
The purpose is to "recognize" the formats (%s %d etc) within the input string.
To do this, it returns an integer that matches the data type.
Then the extracted types are manipulated/handled in other functions.
I want to clarify that my purpose isn't to write formatted types in a string (snprintf etc.) but only to recognize/extract them.
The problem is the crash of my application with error:
Debug Assertion Failed!
Program:
...ers\Alex\source\repos\TestProgram\Debug\test.exe
File: minkernel\crts\ucrt\appcrt\convert\isctype.cpp
Line: 36
Expression: c >= -1 && c <= 255
My code:
#include <iostream>
#include <cstring>
enum Formats
{
TYPE_INT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_NUM
};
typedef struct Format
{
Formats Type;
char Name[5 + 1];
} SFormat;
SFormat FormatsInfo[TYPE_NUM] =
{
{TYPE_INT, "d"},
{TYPE_FLOAT, "f"},
{TYPE_STRING, "s"},
};
int GetFormatType(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return format.Type;
}
return -1;
}
bool isValidFormat(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return true;
}
return false;
}
bool isFindFormat(const char* strBufFormat, size_t stringSize, int& typeFormat)
{
bool foundFormat = false;
std::string stringFormat = "";
for (size_t pos = 0; pos < stringSize; pos++)
{
if (!isalpha(strBufFormat[pos]))
continue;
if (!isdigit(strBufFormat[pos]))
{
stringFormat += strBufFormat[pos];
if (isValidFormat(stringFormat.c_str()))
{
typeFormat = GetFormatType(stringFormat.c_str());
foundFormat = true;
}
}
}
return foundFormat;
}
int main()
{
std::string testString = "some test string with %d arguments"; // crash application
// std::string testString = "%d some test string with arguments"; // not crash application
size_t stringSize = testString.size();
char buf[1024 + 1];
memcpy(buf, testString.c_str(), stringSize);
buf[stringSize] = '\0';
for (size_t pos = 0; pos < stringSize; pos++)
{
if (buf[pos] == '%')
{
if (buf[pos + 1] == '%')
{
pos++;
continue;
}
else
{
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
int typeFormat;
if (isFindFormat(bufFormat, stringSize, typeFormat))
{
std::cout << "type = " << typeFormat << "\n";
// ...
}
}
}
}
}
As I commented in the code, with the first string everything works. While with the second, the application crashes.
I also wanted to ask you is there a better/more performing way to recognize types "%d %s etc" within a string? (even not necessarily returning an int to recognize it).
Thanks.
Let's take a look at this else clause:
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
The variable stringSize was initialized with the size of the original format string. Let's say it's 30 in this case.
Let's say you found the %d code at offset 20. You're going to copy 30 characters, starting at offset 20, into bufFormat. That means you're copying 20 characters past the end of the original string. You could possibly read off the end of the original buf, but that doesn't happen here because buf is large. The third line sets a NUL into the buffer at position 30, again past the end of the data, but your memcpy copied the NUL from buf into bufFormat, so that's where the string in bufFormat will end.
Now bufFormat contains the string "%d arguments." Inside isFindFormat you search for the first isalpha character. Possibly you meant isalnum here? Because we can only get to the isdigit line if the isalpha check passes, and if it's isalpha, it's not isdigit.
In any case, after isalpha passes, isdigit will definitely return false so we enter that if block. Your code will find the right type here. But, the loop doesn't terminate. Instead, it continues scanning up to stringSize characters, which is the stringSize from main, that is, the size of the original format string. But the string you're passing to isFindFormat only contains the part starting at '%'. So you're going to scan past the end of the string and read whatever's in the buffer, which will probably trigger the assertion error you're seeing.
Theres a lot more going on here. You're mixing and matching std::string and C strings; see if you can use std::string::substr instead of copying. You can use std::string::find to find characters in a string. If you have to use C strings, use strcpy instead of memcpy followed by the addition of a NUL.
You could just demand it to a regexp engine which bourned to search through strings
Since C++11 there's direct support, what you have to do is
#include <regex>
then you can match against strings using various methods, for instance regex_match which gives you the possibility, together with an smatch to find out your target with just few lines of codes using standard library
std::smatch sm;
std::regex_match ( testString.cbegin(), testString.cend(), sm, str_expr);
where str_exp is your regex to find what you want specifically
in the sm you have now every matched string against your regexp, which you can print in this way
for (int i = 0; i < sm.size(); ++i)
{
std::cout << "Match:" << sm[i] << std::endl;
}
EDIT:
to better express the result you would achieve i'll include a simple sample below
// target string to be searched against
string target_string = "simple example no.%d is: %s";
// pattern to look for
regex str_exp("(%[sd])");
// match object
smatch sm;
// iteratively search your pattern on the string, excluding parts of the string already matched
cout << "My format strings extracted:" << endl;
while (regex_search(target_string, sm, str_exp))
{
std::cout << sm[0] << std::endl;
target_string = sm.suffix();
}
you can easily add any format string you want modifying the str_exp regex expression.
Here the function (sub) takes two string as input, traversing two string I try to find out if there is any matches in string1 compared to string2. If any that character of string1 is replaced by NULL character. Now this works properly for non repeated character. But if string1 has more than one character that matches once it all replaced by NULL character where i needed only one replacement. For example if string1 and string2 are 122 and 2, after elimination i need 1 2 where i gets now a single 1.
void sub (string str1, string str2){
int i,j,k;
for(i=0; i<=str2.size() ; i++){
for(j=0; j<=str1.size() ; j++ ){
if( str2[i] == str1[j] )
str1[j] = NULL;
}
}
cout<<str1;
expected result is 1 2 instead of 1, if str1=122 and str2=2
You are making things more difficult on yourself than they need to be. The string library provides two functions that can do exactly what you need in a single call.
The member function std::basic_string::find_first_of will locate the first occurrence of a character from string2 in string1 returning the position where it is found.
The std::basic_string::erase function can remove all characters from string1 beginning at that position.
Your sub function will then reduce to:
void sub (std::string& s1, const std::string& s2)
{
s1.erase (s1.find_first_of (s2));
}
A short example using your given strings would be:
#include <iostream>
#include <string>
void sub (std::string& s1, const std::string& s2)
{
s1.erase (s1.find_first_of (s2));
}
int main (void) {
std::string s1 ("122"), s2 ("2");
sub (s1, s2);
std::cout << "s1: " << s1 << "\ns2: " << s2 << '\n';
}
Example Use/Output
$ ./bin/sub1at2
s1: 1
s2: 2
Look things over and let me know if you have further questions.
You can't remove a character from a string by setting it to NULL. The length of the string will remain the same. But one way to simulate the removal of the duplicates is to return a new string that matches the return conditions.
First iterate over the second string and use a hash table to map each character in s2 to true. Then iterate over s1 and add the current character to a new string only if the character in the hash table maps to false. Remapping the character to false after this condition ensures that all but one of the number of characters is written to the result string.
string remove_first_duplicates(string s1, string s2) {
unordered_map<char, bool> m;
string result;
for (char i : s2) m[i] = true;
for (char i : s1) {
if (!m[i]) result += i;
m[i] = false;
}
return result;
}
NULL is not a character-constant, even if \0 is the null character. It's a macro for a null pointer constant, and for historical reasons is often defined as 0, though it might be nullptr or any other null pointer constant.
Zeroing out characters does not stop them being part of the string. for that, you must move the remaining ones and adjust the length.
If you only want to do it once, on the first match, leve the function with return afterwards.
Consider separating it into two functions: One for finding a match, and one calling that and using the result for removing the first match.
As far as I understood your question, you want to remove one char from str1 corresponding to a match in str2.
void sub(string str1, string str2)
{
int i = 0, j = 0;
while (j < str2.size())
{
if (str1[i] == str2[j])
{
str1[i] = NULL; // could use str1.erase(i,1)
i = 0;
j += 1;
continue;
}
else
i += 1;
if (i == str1.size() - 1)
{
i = 0;
j += 1;
}
}
cout<<str1<<endl;
}
This will yield the output you desire. But this will produce NULL char in str1, better option is to use erase functionality from std::string.
I'm currently making a quick Hangman game and I'm struggling to take the correctly guessed letters from the word and insert them into the string that I show the user as they play the game. This is my code so far:
std::string word_to_guess = "ataamataesaa";
std::string word_to_fill(word_to_guess.length(), '-');
char user_guess = 'a';
for (auto &character : word_to_guess) {
if (character == user_guess) {
std::size_t index = word_to_guess.find(&character);
word_to_fill[index] = user_guess;
}
}
std::cout << word_to_fill;
This almost works however it ignores the last two As of the string to guess which I cannot understand.
"Find" will return only the first occurrence.
Instead of iterating over characters, iterate simultaneously over the indexes of both word_to_guess and word_to_fill.
for (int i = 0 ; i < word_to_fill.length ; ++i) {
if (word_to_guess[i] == user_guess) {
word_to_fill[i] = user_guess;
}
}
Been working on this program which requires the use of a function that compares a string input by the user and gives the user the opportunity to leave the characters that he/she doesn't know out of the input, replacing them with * . The input represents a license-plate of a car that has 6 characters (for instance ABC123) and the user is allowed to leave any of those characters out (for instance AB** 23 or ** C12* etc.). So the function needs to return all objects that match the characters in the right position, but it cannot return if, say, A is in the right position but any of the other characters are not. The user is, however, allowed to only enter A* * * * *, for instance, and the function should return all objects that have A in the first position.
What I did was use a function to remove all the asterisks from the input string, then create sub-strings and send them to the function as a vector.
string removeAsterisk(string &rStr)// Function to remove asterisks from the string, if any.
{
stringstream strStream;
string delimiters = "*";
size_t current;
size_t next = -1;
do
{
current = next + 1;
next = rStr.find_first_of( delimiters, current );
strStream << rStr.substr( current, next - current ) << " ";
}
while (next != string::npos);
return strStream.str();
}
int main()
{
string newLicensePlateIn;
newLicensePlateIn = removeAsterisk(licensePlateIn);
string buf; // Have a buffer string
stringstream ss(newLicensePlateIn); // Insert the string into a stream
vector<string> tokens; // Create vector to hold our words
while (ss >> buf)
tokens.push_back(buf);
myRegister.showAllLicense(tokens);
}
The class function that receives the vector currently looks something like this:
void VehicleRegister::showAllLicense(vector<string>& tokens)//NOT FUNCTIONAL
{
cout << "\nShowing all matching vehicles: " << endl;
for (int i = 0; i < nrOfVehicles; i++)
{
if(tokens[i].compare(vehicles[i]->getLicensePlate()) == 0)
{
cout << vehicles[i]->toString() << endl;
}
}
}
If anyone understand what I'm trying to do and might have some ideas, please feel free to reply, I would appreciate any advice.
Thanks for reading this/ A.
Just iterate through the characters, comparing one at a time. If either character is an asterisk, consider that a match, otherwise compare them for equality. For example:
bool LicensePlateMatch(std::string const & lhs, std::string const & rhs)
{
assert(lhs.size() == 6);
assert(rhs.size() == 6);
for (int i=0; i<6; ++i)
{
if (lhs[i] == '*' || rhs[i] == '*')
continue;
if (lhs[i] != rhs[i])
return false;
}
return true;
}
Actually, you don't have to restrict it to 6 characters. You may want to allow for vanity plates. In that case, just ensure both strings have the same length, then iterate through all the character positions instead of hardcoding 6 in there.
i need to create a function that will accept a directory path. But in order for the compiler to read backslash in i need to create a function that will make a one backslash into 2 backslash.. so far this are my codes:
string stripPath(string path)
{
char newpath[99999];
//char *pathlong;
char temp;
strcpy_s(newpath, path.c_str());
//pathlong = newpath;
int arrlength = sizeof(newpath);
for (int i = 0; i <= arrlength ;i++)
{
if(newpath[i] == '\\')
{
newpath[i] += '\\';
i++;
}
}
path = newpath;
return path;
}
this code receives an input from a user which is a directory path with single backslash.
the problem is it gives a dirty text output;
int arrlength = sizeof(newpath); causes the size of your entire array (in chars) to be assigned to arrlength. This means you are iterating over 99999 characters in the array, even if the path is shorter (which it probably is).
Your loop condition also allows goes one past the bounds of the array (since the last (99999th) element is actually at index 99998, not 99999 -- arrays are zero-based):
for (int i = 0; newpath[i]] != '\0'; i++)
Also, there is no reason to copy the string into a character array first, when you can loop over the string object directly.
In any case, there is no need to escape backslashes from user input. The backslash is a single character like any other; it is only special when embedded in string literals in your code.
In this line:
if(newpath[i] = '\\')
replace = with ==.
In this line:
newpath[i] += '\\';
This is supposed to add a \ into the string (I think that's what you want), but it actually does some funky char math on the current character. So instead of inserting a character, you are corrupting the data.
Try this instead:
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char ** argv) {
std::string a("hello\\ world");
std::stringstream ss;
for (int i = 0; i < a.length(); ++i) {
if (a[i] == '\\') {
ss << "\\\\";
}
else {
ss << a[i];
}
}
std::cout << ss.str() << std::endl;
return 0;
}
lots wrong. did not test this but it will get you closer
http://www.cplusplus.com/reference/string/string/
string stripPath(string path)
{
string newpath;
for (int i = 0; i <= path.length() ;i++)
{
if(path.at(i) == '\\')
{
newpath.append(path.at(i));
newpath.append(path.at(i));
}
else
newpath.append(path.at(i));
}
return newpath;
}
But in order for the compiler to read
backslash in i need to create a
function that will make a one
backslash into 2 backslash
The compiler only reads string when you compile, and in that case you will need two as the first back slash will be an escape character. So if you were to have a static path string in code you would have to do something like this:
std::string path = "C:\\SomeFolder\\SomeTextFile.txt";
The compiler will never actually call your function only compile it. So writing a function like this so the compiler can read a string is not going to solve your problem.
The condition if (newpath[i] = '\\') should be if (newpath[i] == '\\').
The statement newpath[i] += '\\'; will not give the intended result of concatenation. It will instead add the integral value of '\\' to newpath[i].
Moreover why are you using a char newpath[99999]; array inside the function. newpath could be std::string newpath.
int main()
{
std::string path = "c:\\test\\test2\\test3\\test4";
std::cout << "orignal path: " << path << std::endl;
size_t found = 0, next = 0;
while( (found = path.find('\\', next)) != std::string::npos )
{
path.insert(found, "\\");
next = found+4;
}
std::cout << "path with double slash: " << path << std::endl;
return 0;
}