in c++ how to search just a part of a string starting from startIndex and ending after some count of chars. in some cases I just need to search the first 5 chars for a special char or string why will I have to come over the whole string it may be 1000 chars or multiples of that. what I know in c++ run time library, all functions don't support something like that for example strchr it will search all of the string, I don't want that I want to compare a specific part of the string from [] to []. I've seen a solution for that problem using wmemchr but I need it to be dependent on the currently selected locale, if anybody know how to do that, I'd be grateful.
Also how to compare just 2 chars directly regarding to the locale?
I'm not aware of a way to do this directly with a standard library, but you could make your own function and strstr pretty easily.
/* Find str1 within str2, limiting str2 to n characters. */
char * strnstr( char * str1, const char * str2, size_t n )
{
char * ret;
char temp = str1[n]; // save our char at n
str2[n] = NULL; // null terminate str2 at n
ret = strstr( str1, str2 ); // call into strstr normally
str2[n] = temp; // restore char so str2 is unmodified
return ret;
}
For your second question:
Also how to compare just 2 chars directly regarding to the locale?
I'm not sure what you mean. Are you asking how to compare two characters directly? If so, you can just compare like any other values.
if( str1[n] == str2[n] ) { ...do something... }
You can use std::substr to limit your search area:
std::string str = load_some_data();
size_t pos = str.substr(5).find('a');
I solved it like that
int64 Compare(CHAR c1, CHAR c2, bool ignoreCase = false)
{
return ignoreCase ? _strnicoll(&c1, &c2, 1) : _strncoll(&c1, &c2, 1);
}
int64 IndexOf(const CHAR* buffer, CHAR c, uint count, bool ignoreCase = false)
{
for (uint i =0; i < count; i++)
{
if (Compare(*(buffer + i), c, ignoreCase) == 0)
{
return i;
}
}
return npos;
}
int64 LastIndexOf(const CHAR* buffer, CHAR c, uint count, bool ignoreCase = false)
{
while(--count >= 0)
{
if (Compare(*(buffer + count), c, ignoreCase) == 0)
{
return count;
}
}
return npos;
}
npos = -1
and to specify the start index pass to (buffer + startIndex) as the buffer to the second or the third method
Related
My function must process strings that look like say hello y(5) or data |x(3)|, and I need to be able to extract the integer shown and store it into a separate int variable called address. However, some strings passing through will not have any integers, and for these the address must default to 0. When a string contains an integer, it will always be in between parentheses. I've attempted to use sscanf, but, being very new to sscanf, I'm encountering problems.. For some reason, the address always reads as 0. Here's my code:
void process(string info)
{
int address = 0; // set to 0 in case info contains no digits
sscanf(info.c_str(), "%d", address);
.
.
.
// remainder of code makes other function calls using the address, etc
}
Any ideas as to why the sscanf fails to find the integer in between parentheses? Thanks!
why the sscanf fails to find the integer in between parentheses
The "%d" in sscanf(info.c_str(), "%d", address) will cause sscanf() to stop scanning once a non-numeric sequence detected. Text like "(5)" will simply stop scanning at the "(".
Instead code need to to skip over non-numeric text.
Pseudo-code
in a loop
search for any of "-+0123456789"
if not found return 0
convert from that point using sscanf() or strtol()
if that succeeds, return number
else advance to next character
Sample code
int address;
const char *p = info.c_str();
for (;;) {
p += strcspn(p, "0123456789+-");
if (*p == 0) return 0;
if (sscanf(p, "%d", &address) == 1) {
return address;
}
p++;
}
Notes:
The strcspn function computes the length of the maximum initial segment of the string pointed to by s1 which consists entirely of characters not from the string pointed to by s2. C11 7.24.5.3 2
If code wants to rely on " it will always be in between parentheses." and input like "abc()def(123)" does not occur which has preceding non-numeric data between ().:
const char *p = info.c_str();
int address;
if (sscanf(p, "%*[^(](%d", &address)==1) {
return address;
}
return 0;
or simply
int address = 0;
sscanf(info.c_str(), "%*[^(](%d", &address);
return address;
You could use something as simple as this where strchr finds the first occurrence of "(" then use atoi to return the integer which will stop at the first non-digit.
char s1[] = "hello y(5)";
char s2[] = "data [x(3)]";
char s3[] = "hello";
int a1 = 0;
int a2 = 0;
int a3 = 0;
char* tok = strchr( s1, '(');
if (tok != NULL)
a1 = atoi(tok+1);
tok = strchr( s2, '(');
if (tok != NULL)
a2 = atoi(tok+1);
tok = strchr(s3,'(');
if (tok != NULL)
a3 = atoi(tok+1);
printf( "a1=%d, a2=%d, a3=%d", a1,a2,a3);
return 0;
When a string contains an integer, it will always be in between
parentheses
To strictly conform with this requirement you can try:
void process(string info)
{
int address;
char c = '5'; //any value other than ) should work
sscanf(info.c_str(), "%*[^(](%d%c", &address, &c);
if(c != ')') address = 0;
.
.
.
}
link to a solution
int address;
sscanf(info.c_str(), "%*[^0-9]%d", &address);
printf("%d", address);
this should extract the integer between the parenthesis
My C++ class is going over C-style strings and working with pointers. I'm to write a function that has three parameters: a char * s1, a const char * s2, and a size_t max, which represents that maximum size of the s1 buffer. I am to append the characters in s2 to the end of s1. The directions advise me to make sure there is only one '\0' at the end of the combined characters and I am not to go beyond the end of the buffer I'm asked to copy to. The function will return a pointer to the first character in s1.
I cannot use any functions in the standard library. What I can use are pointers, pointer arithmetic or array notation.
I've started, but not sure where to go.
const char * myFunction (char * s1, const char * s2, size_t max)
{
char * begin = s1;
while (*s1) s1++;
while ((s1 < begin + max - 1) && (*s2 != '\0')) {
*s1++ = *s2++;
}
return s1;
}
Not sure what to do after reaching the end of s1. How would I put s2 to the end of s1?
I cannot use any functions in the standard library.
The only required one would be strlen(), I think. Roll your own:
#define min(a,b) ((a) < (b)) ? (a) : (b)
size_t str_length(const char* s)
{
size_t len = 0;
for( ; *s; ++s, ++len);
return len;
}
const char * append (char * s1, const char * s2, size_t max)
{
if(!s1 || !s2) //If either of strings is NULL, nothing to be done
return s1;
size_t s1_length = str_length(s1);
if(s1_length < max - 1) //If there is a room in s1...
{
size_t s2_length = str_length(s2); //Get length of s2
size_t append_size = min(s2_length, max - s1_length - 1); //Make sure we won't copy more than buffer can hold
if(append_size > 0)
{
memcpy(s1 + s1_length, s2, append_size); //This will overwrite null terminator in 's1'
s1[s1_length + append_size] = 0;
}
}
return s1;
}
Test:
int main(void)
{
char dest[64] = "This is a test";
append(dest, " of strings appending", 64);
printf("%s (length: %d)\n", dest, str_length(dest));
append(dest, " of appending too long string, that will probably not fit inside destination buffer", 64);
printf("%s (length: %d)\n", dest, str_length(dest));
return 0;
}
Output:
This is a test of strings appending (length: 35)
This is a test of strings appending of appending too long strin (length: 63)
Here is working sample.
Let's say I have a constant c-style string say
const char* msg = "fred,jim,345,7665";
I'd like to tokenize this and read out the individual fields but for performance reasons I don't want to make a copy. How can I do this?
Obviously strtok takes a non-constant pointer and boost::tokenizer is an option but I am unsure what is doing behind the scenes.
Inevitably you will require some copy of the string, even if it is a substring being copied.
If you have a strtok_r function, you can use that, but it will still require a mutable string to do its work. Beware, however, as not all systems provide the function (e.g. Windows), which is why I've provided an implementation here. It works by requiring an additional parameter: a pointer to a C string to save the address of the next match. This allows for it to be more reentrant (thread-safe) in theory. However, you'll still be mutating the value. You could modify it to suit your needs if you like, perhaps copying N bytes into a destination buffer and null-terminating that buffer to avoid the need to modify the source string.
/*
Usage:
char *tok;
char *savep;
tok = mystrtok_r (somestr, ",", &savep);
while (NULL != tok)
{
/* Do something with `tok'. */
tok = mystrtok_r (NULL, ",", &savep);
}
*/
char *
mystrtok_r (char *str, const char *delims, char **nextp)
{
if (str == NULL)
str = *nextp;
str += strspn (str, delims);
*nextp = str + strcspn (str, delims);
**nextp = 0;
if (*str == 0)
return NULL;
++*nextp;
return str;
}
It depends on how you're going to use it.
If you want to get the next token, and then the next (like an iteration over the string, then you only really need to copy the current token into memory.
long strtok2( char *strDest, const char *strSrc, const char cTok, long lOffset, long lMax)
{
if(lMax > 0)
{
strSrc += lOffset;
char * start = strDest;
while(--lMax && *strSrc != cTok && (*strDest++ = * strSrc++) );
*strDest = 0; //for when the token was found, not the null.
return strDest - start - 1; //the length of the token
}
return 0;
}
I snagged a simple strcpy from http://vijayinterviewquestions.blogspot.com.au/2007/07/implement-strcpy-function.html
const char* msg = "fred,jim,345,7665";
char * buffer[20];
long offset = 0;
while(length = strtok2(buffer, msg, ',', offset, 20))
{
cout << buffer;
offset += (length+1);
}
Well, without a little more detail it's hard to know exactly what you want. I'll guess you are parsing delimited items where consecutive delimiters should be treated as zero length tokens (which is usually correct for comma separated elements). I'm also assuming a blank line counts as a single zero length token. This is how I'd approach it:
const char *token_begin = msg;
int length;
for(;;)
{
length = 0;
while(!isDelimiter(token_begin[length])) //< must include \0 as delimiter
++length;
//..do something here with token. token is at: token_begin[0..length)
if ( token_begin[length] != 0 )
token_begin = &token_begin[length+1]; //skip beyond non-null delimiter
else
break; //token null terminated. exit
}
If you are going to store the tokens somewhere then a copy will be necessary in any case and strtok does this nicely by using the string a placing null terminating character inside it.
The only other option I see to avoid copying it is a lexer which reads the string and through a state machine produces tokens by scanning the string and storing the partial results in a buffer but every token should in any case be stored at least in a null terminated string to you are not really saving anything.
Here is my proposal, my code is structured and use a global variable pos(I know global variable are a bad practice but is only to give you the idea), you can replace it with a data member if you need OOP.
int position, messageLength;
char token[MAX]; // MAX = Value greater than the maximum length
// of the tokens(e.g. 1,000);
bool hasNext()
{
return position < messageLength;
}
char* next(const char* message)
{
int i = 0;
while (position < messageLength && message[position] != ',') {
token[i++] = message[position];
position++;
}
position++; // ',' found
token[i] = '\0';
return token;
}
int main(int argc, char **argv)
{
const char* msg = "fred,jim,345,7665";
position = 0;
messageLength = strlen(msg);
while (hasNext())
cout << next(msg) << endl;
return EXIT_SUCCESS;
}
It is possible to delete all characters of a string that is immediately followed by two vowels, without the aid of a char array, using instead exclusively the "string" library ?
For example:
priamo -> iamo
The algorithm should be:
Cycling the string making a for loop from 0 to string.length()-2 to prevent overflow
Compare pairs of characters with a char array containing all the vowels
Using "Erase" function in the string library to delete positions before the vowels
but I have no idea how to implement the second point without the help of an array of characters. Any suggestions?
I'd suggest using std::adjacent_find:
std::string s{"priamo"};
auto is_vowel = [](char c) -> bool {
static const char vowels[] = "aeiou";
return std::any_of(std::begin(vowels), std::prev(std::end(vowels)),
[c](char d) { return c == d; } );
};
auto it = std::adjacent_find(s.crbegin(), s.crend(),
[&](char c, char d) { return is_vowel(c) && is_vowel(d); }).base();
if (it != s.cbegin())
s.erase(s.cbegin(), std::prev(it, 2));
What they meant by saying without the aid of char array probably means that you must not do any kind of buffering. You can use const char vowels[]="aeiou"; of course.
Well, this is probably wrong but should give you the idea and a base for others to correct:
string str="priamo";
const char vowels[]="aeiou";
size_t pos=0;
size_t vowels_piled_up=0;
while((pos=str.find_first_of(&vowels[0], pos+vowels_piled_up))!=string::npos)
{
if((pos+1)+1 >= str.size())//break if it is on the last 2
break;
if((strchr(&vowels[0], str[pos+1]))!=NULL)
{
str.erase(vowels_piled_up, pos-1-vowels_piled_up);
pos=0;
vowels_piled_up+=2;
}
else
++pos;
}
How would I manually concatenate two char arrays without using the strncpy function?
Can I just say char1 + char2?
Or would I have to write a for loop to get individual elements and add them like this:
addchar[0] = char1[0];
addchar[1] = char1[1];
etc
etc
addchar[n] = char2[0];
addchar[n+1] = char2[1];
etc
etc
To clarify, if
char1 = "happy"
char2 = "birthday"
I want addchar to = happybirthday
For a C-only solution use strncat:
char destination[80] = "";
char string1[] = "Hello";
char string2[] = " World!";
/* Copy string1 to destination */
strncat(destination, string1, sizeof(destination));
/* Append string2 to destination */
strncat(destination, string2, sizeof(destination) - sizeof(string1));
Note that the strn* family of string functions are safer than the ones without n, because they avoid the possibility of buffer overruns.
For a C++ solution, simply use std::string and operator+ or operator+=:
std::string destination("Hello ");
destination += "World";
destination += '!';
If you consider two trivial loops to be "manual", then yes, without using the standard library this is the only way.
char *append(const char *a, const char *b) {
int i = 0;
size_t na = strlen(a);
size_t nb = strlen(b);
char *r = (char*)calloc(na + nb + 1, 1);
for (i = 0; i < na; i++) {
r[i] = a[i];
}
for (i = 0; i < nb; i++) {
r[na + i] = b[i];
}
return r;
}
Remember to call free.
If you're using c++ just use an std::string. With std::strings, the + operator is supported, so you can do string1+string2.
Without using library functions, here is the procedure:
1. Point to the first character in string1.
2. While the current character at the pointer is not null, increment the pointer.
3. Create a "source" pointer pointing to string2.
4. While the character at the "source" location is not null:
4.1. Copy the character from the "source" location to the location pointed to by the String1 pointer.
4.2. Increment both pointers.
Unless this is homework, use C++ std::string for your text.
If you must use C style strings, use the library functions.
Library functions are optimized and validated, reducing your development time.
Alright, you want something like this:
char1 + char2
First, let's see the insane solution:
C:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = (char*)malloc(length);
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
C++:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = new char[length];
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
Now, let's see the sane solution:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length = strlen(a_Left) + strlen(a_Right);
char* result = new char[length];
strcpy(result, a_Left);
strcat(result, a_Right);
return result;
}
So, was this homework? I don't really care.
If it was, ask yourself: what did you learn?