atomicgs12
asked on
Find last occurrence of any valid character in a string C++
I have a C++ project and I read a line from a file, I'm using fgets but I can use anything. With that line I would like to find the last position, in the string, that contains a valid character or number, i.e. 0-9 or a-Z. I don't really what to create a string that holds all the numbers and characters to use as a compare I would like the most eligant was to find the last vaild character/number in the string so I can extract a variable size word from the string.
Thanks
Thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
::isalnum in combination with phoffric's comment above would probably be the way to go.
Since the comparison string is user defined, and only alphanumerics are included, then there should be no need to further test for alphanumerics.
However, you can write your own loop searching from the end of the string testing for alphanumerics using isalnum and not using the functions in the first post.
However, you can write your own loop searching from the end of the string testing for alphanumerics using isalnum and not using the functions in the first post.
ASKER
Doesn't all these examples mean I have to create a comparison string of "0-9, a-z, A-Z", which is what I did NOT want to do?
Thanks
Thanks
OP stated I don't really what to create a string that holds all the numbers and characters to use as a compare, and unless I'm misunderstanding something strpbrk, strcspn, strtok, etc all require a string to hold all the numbers and characters against which to compare, which is why I suggested isalnum - maybe I'm being too literal. ;)
string test("one two three---");
string::iterator it = find_if(test.rbegin(), test.rend(), isalnum).base();
int indexOfLastAlphaNumeric = it - test.begin() - 1;
Using isalnum is likely to be a performance improvement over the other mentioned functions since it doesn't necessarily have to compare each char in your string against the 26*2+10 valid chars. Instead depending upon the locale, it will do just a few tests. If ASCII chars, it would be
( 'a' <= ch && ch <= 'z') || ( 'A' <= ch && ch <= 'Z') for the alphas, and similar for the digits.
( 'a' <= ch && ch <= 'z') || ( 'A' <= ch && ch <= 'Z') for the alphas, and similar for the digits.
>> which is what I did NOT want to do?
I misunderstood the OP.
I misunderstood the OP.
I guess you don't necessarily need to know the index of the last non-alpha-numeric, if, for example, you just want the last word in a given string:
http://www.cplusplus.com/reference/algorithm/find_if/
http://www.cplusplus.com/reference/std/functional/not1/
http://www.cplusplus.com/reference/string/string/
http://www.cplusplus.com/reference/algorithm/find_if/
http://www.cplusplus.com/reference/std/functional/not1/
http://www.cplusplus.com/reference/string/string/
Enter a string: one---two---three---
The last word in the line is: three
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
void GetLastWord(string &source, string &dest)
{
string::reverse_iterator end = find_if(source.rbegin(), source.rend(), ::isalnum);
string::iterator start = find_if(end, source.rend(), not1(ptr_fun(isalnum))).base();
dest = string(start, end.base());
}
int main(int argc, char *argv[])
{
string input, lastWord;
cout << "Enter a string: ";
getline(cin, input);
GetLastWord(input, lastWord);
cout << "The last word in the line is: " << lastWord << endl;
cin.get();
}
While perhaps not the most elegant solution, I would think the most strait forward solution would be to use strlen to find the end of the string, position a char* to point to that last char of the string, then use the logic like what phoffric shows two posts up to determine if what char* points to is a valid charactor or not. If the character is invalid (i.e. not a-z, A-Z, or 0-9) then back the char* up one time until a valid character is reached (or the start of the string is reached).
char Read[100];
char* pLast;
fgets( Read );
pLast = Read + strlen( Read );
while( pLast > Read )
{
char ch = *pLast;
if( 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '0' <= ch && ch <= '9')
break;
pLast--;
}
if( pLast == Read )
pLast = NULL; //Flags that there were no valid characters in the string
char Read[100];
char* pLast;
fgets( Read );
pLast = Read + strlen( Read );
while( pLast > Read )
{
char ch = *pLast;
if( 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '0' <= ch && ch <= '9')
break;
pLast--;
}
if( pLast == Read )
pLast = NULL; //Flags that there were no valid characters in the string
why not just use isalnum(ch) instead of the if statement (which assumes ASCII chars)? You could just use:
if( isalnum(ch) )
break;
if( isalnum(ch) )
break;
>> Doesn't all these examples mean I have to create a comparison string of "0-9, a-z, A-Z", which is what I did NOT want to do?
To which I replied, "I misunderstood the OP."
So, I think you may have accepted my answer which is not what you wanted.
To which I replied, "I misunderstood the OP."
So, I think you may have accepted my answer which is not what you wanted.
ASKER
Actually I should have divided it up, I ended up using your hint of find_last_of and tgerbert's std::string .begin, .end
I'm not concerned about the points, so long as the correct answer is selected so someone else reading this thread in the future might find it useful, and that appears to be the case so I say leave it as-is.