473,791 Members | 2,861 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Iterating through a string

Hi Guys,

I have a string which contains data elements separated by spaces. I also
have a function which returns the number of characters from the beginning of
the string for a given number of spaces. I am using a loop with strchr for
the number of spaces, and I was just wondering if there was a more efficient
(ie faster) way of achieving this. Any ideas please? Current function code
below:

int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

do {
b = strchr(b, ' '); // find next space
++i; ++b; // increment space counter and pointer
} while(i<Spaces && b != NULL);

if(b) return b - DataStr.c_str() ;
else return -1;
}
Any help is appreciated,
Thanks for reading,
Steve.
Jul 22 '05 #1
16 4352
On Tue, 8 Jun 2004 22:42:36 +0100 in comp.lang.c++, "Steve"
<st*******@hotm ail.com> wrote,
the string for a given number of spaces. I am using a loop with strchr for
the number of spaces, and I was just wondering if there was a more efficient
(ie faster) way of achieving this.


For efficiency, avoid going over the same ground more than once, i.e.
continue from the previous position and do not restart at the beginning
of the string.

Use string::find() functions rather than .c_str() and dropping down to
low-level old library strchr().

Do not subtract one .c_str() from another. There is no guarantee that
..c_str() will point to the same buffer every time.

See if using a string splitter function would suit you better?
http://groups.google.com/gr*********....earthlink.net

Jul 22 '05 #2
There's probably a standard library input stream class which you can use to
suck out the pieces of data you want.
If you want to roll your own, you could create a specialized iterator object
which takes your string and lets you iterate over it. It seems that you
are always starting from the beginning when you want the next position and
count through the string to find the next one. By using an object to wrap
the
string, you could maintain this state information in the object and wouldn't
need to compute it from scratch every time.
class FooBar
{
public:
FooBar( const std::string& DataStr )
:_DataStr(DataS tr), _position(0)
{
// move position to point to the first data item.
}

std::string GetDataItem( ) const
{
// return a string representing the next data item.
}
bool IsValid() const ; // return true if there are more items to return,
false otherwise.
bool Next(); // advance through datastring until end of string or next
data item is found,
// update position counter.

bool First() ; // wind back position to be at the first data item, so we
can iterate again over
// the string.

private:
const std::string _DataStr
int _position;

};

.......

FooBar myfoobar( DataStr);

for ( myfoobar.First( ) ; myfoobar.IsVali d( DataItem); myfoobar.Next() )
{
string ds = myfoobar.GetDat aItem();

}

"Steve" <st*******@hotm ail.com> wrote in message
news:Ohrxc.1911 $ud5.1728@newsf e4-gui...
Hi Guys,

I have a string which contains data elements separated by spaces. I also
have a function which returns the number of characters from the beginning of the string for a given number of spaces. I am using a loop with strchr for
the number of spaces, and I was just wondering if there was a more efficient (ie faster) way of achieving this. Any ideas please? Current function code
below:

int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

do {
b = strchr(b, ' '); // find next space
++i; ++b; // increment space counter and pointer
} while(i<Spaces && b != NULL);

if(b) return b - DataStr.c_str() ;
else return -1;
}
Any help is appreciated,
Thanks for reading,
Steve.

Jul 22 '05 #3
In article <Ohrxc.1911$ud5 .1728@newsfe4-gui>,
"Steve" <st*******@hotm ail.com> wrote:
Hi Guys,

I have a string which contains data elements separated by spaces. I also
have a function which returns the number of characters from the beginning of
the string for a given number of spaces. I am using a loop with strchr for
the number of spaces, and I was just wondering if there was a more efficient
(ie faster) way of achieving this. Any ideas please? Current function code
below:

int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

do {
b = strchr(b, ' '); // find next space
++i; ++b; // increment space counter and pointer
} while(i<Spaces && b != NULL);

if(b) return b - DataStr.c_str() ;
else return -1;
}


I don't think your code does what you want it to do, but since you
didn't show what you wanted, I'm not sure.

I wrote this:

int main() {
string elements( "aaa bbb ccc ddd" );
for ( int x = 0; x < 10; ++x ) {
int pos = GetNewPosition( elements, x );
cout << pos << endl;
}
}

and got this output:

4
4
8
12
-654603

*crash*

I'm not entirely sure what your code is supposed to do, but this
function may be more in line with what you are looking for:

int GetNewPosition( const std::string& DataStr, int Spaces)
{
assert( Spaces >= 0 );
int result = -1;
unsigned working = DataStr.find_fi rst_not_of( ' ' );
// strictly speaking 'working != string::npos' in the
// below isn't necessary. It makes the code more efficient.
while ( working != string::npos && Spaces-- ) {
working = DataStr.find_fi rst_not_of( ' ',
DataStr.find( ' ', working ) );
}
assert( working == string::npos || working <= INT_MAX );
if ( working != string::npos )
result = working;
return result;
}

On most computers, I could have done without the 'working' variable,
instead using the 'result' variable. However, from what I understand -1
== string::npos is not guaranteed to be true.

Also note the two asserts in the function. They check the assumptions
made in the algorighm (a) Spaces isn't negitive (it may work with a
negitive value for Spaces, but I didn't test it, (b) that the position
of the char we are looking for is small enough to fit in an int (what
would it take to generate a string that would cause this assert to fire?)
Jul 22 '05 #4
In article <25************ ********@comcas t.com>,
"Dave Townsend" <da********@com cast.net> wrote:
If you want to roll your own, you could create a specialized iterator object
which takes your string and lets you iterate over it.
If the OP decides to do this, I think he would be better off if he
followed the standard iterator concept.

class FooBar
{
public:
FooBar( const std::string& DataStr )
:_DataStr(DataS tr), _position(0)
{
// move position to point to the first data item.
}

std::string GetDataItem( ) const
{
// return a string representing the next data item.
}
bool IsValid() const ; // return true if there are more items to return,
false otherwise.
bool Next(); // advance through datastring until end of string or next
data item is found,
// update position counter.

bool First() ; // wind back position to be at the first data item, so we
can iterate again over
// the string.

private:
const std::string _DataStr
int _position;

};

The class below is a standard input iterator:

class word_iterator:
public std::iterator<s td::input_itera tor_tag, std::string>
{
friend bool operator==( const word_iterator& lhs,
const word_iterator& rhs );
friend std::ostream& operator<<( std::ostream& lhs,
const word_iterator& rhs ); // for testing only

const std::string* str;
std::string::si ze_type pos;

public:
word_iterator( const std::string* s = 0 ):
str( s && !s->empty() ? s: 0 ),
pos(std::string ::npos) {
if ( s )
pos = s->find_first_not _of( ' ' );
}

const std::string operator*() const {
assert( pos != std::string::np os );
unsigned len = str->find( ' ', pos );
if ( len < std::string::np os ) len -= pos;
return str->substr( pos, len );
}

const std::string* operator->() const {
// is there a better way to write this function?
static std::string bit;
bit = **this;
return &bit;
}

const word_iterator& operator++() {
assert( pos != std::string::np os );
if ( pos != std::string::np os )
pos = str->find_first_not _of( ' ', str->find( ' ', pos ) );
return *this;
}

const word_iterator operator++(int) {
word_iterator tmp( *this );
++(*this);
return tmp;
}
};

bool operator==( const word_iterator& lhs, const word_iterator& rhs ) {
// comparing iterators from two different containers is undefined
return lhs.pos == rhs.pos;
}

bool operator!=( const word_iterator& lhs, const word_iterator& rhs ) {
return !( lhs == rhs );
}

std::ostream& operator<<( std::ostream& lhs, const word_iterator& rhs ) {
// for testing purposes only
lhs << "Pos: " << rhs.pos << " of string: '"
<< ((rhs.str) ? *rhs.str : std::string("NU LL")) << "'";
return lhs;
}
FooBar myfoobar( DataStr);

for ( myfoobar.First( ) ; myfoobar.IsVali d( DataItem); myfoobar.Next() )
{
string ds = myfoobar.GetDat aItem();

}


Mine would be used like this:

string s;
//...
for ( word_iterator x( &s ); x != word_iterator() ; ++x )
cout << "word: " << *x
<< " is " << x->length() << "long.\n";
Or you could use it in the standard algorithms:

string s;
//...
copy( word_iterator(& s), word_iterator() ,
ostream_iterato r<string>(cout , "\n"));
Jul 22 '05 #5
"David Harmon" <so****@netcom. com.invalid> wrote in message
Use string::find() functions rather than .c_str() and dropping down to
low-level old library strchr().


The strcmp, strchr, memcmp functions may be more efficient than std::equal,
std::find because of block optimizations (ie. builtin CPU instructions to
analyze an entire block of bytes at once). In principle an implementation
may specialize std::find etc to call strchr, but I have yet to find one.
Jul 22 '05 #6
"Steve" <st*******@hotm ail.com> wrote in message
news:Ohrxc.1911 $ud5.1728@newsf e4-gui...
int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

do {
b = strchr(b, ' '); // find next space
++i; ++b; // increment space counter and pointer
} while(i<Spaces && b != NULL);

if(b) return b - DataStr.c_str() ;
else return -1;
}


In addition to the other points, what happens when strchr returns NULL?
Your code does ++b, which may (and should) crash the program.

As Dave points out, you should store the result of the first DataStr.c_str
in a pointer, and avoid calling the function a second time as it is allowed
to return a different pointer.
Jul 22 '05 #7

"Steve" <st*******@hotm ail.com> wrote in message
news:Ohrxc.1911 $ud5.1728@newsf e4-gui...
Hi Guys,

I have a string which contains data elements separated by spaces. I also
have a function which returns the number of characters from the beginning of the string for a given number of spaces. I am using a loop with strchr for
the number of spaces, and I was just wondering if there was a more efficient (ie faster) way of achieving this. Any ideas please? Current function code
below:

int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

do {
b = strchr(b, ' '); // find next space
++i; ++b; // increment space counter and pointer
} while(i<Spaces && b != NULL);

if(b) return b - DataStr.c_str() ;
else return -1;
}

Your current function is bugged. If there are no spaces, then b == NULL,
then you increment b, then you test it for NULL. That isn't going to work.
You also have a completely gratuitous const_cast in your code.

It's quite a good example of how newbies worry about efficiency without
other more important considerations such as writing working code, and
writing clear code.

However strchr is probably the fastest way to do it, however as with all
these questions there is no official answer as to which method is fastest.
The C++ standard makes no mention of which functions or techniques are
faster than others, the only way to tell for sure is try different methods
and time them.

Here's my version, completely untested, so apologies in advance for any
bugs.

int GetNewPosition( const std::string& DataStr, int Spaces)
{
const char* start = DataStr.c_str() ;
const char* p = start;
for (int i = 0; i < Spaces; ++i)
{
if (p == NULL)
return -1;
p = strchr(p + 1, ' ');
}
return p - start;
}

john
Jul 22 '05 #8
"John Harrison" <jo************ *@hotmail.com> wrote in message
news:2inljvFpkd 8vU1@uni-
"Steve" <st*******@hotm ail.com> wrote in message
int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of string

You also have a completely gratuitous const_cast in your code.


This last point seems fine to me. The original object was obviously
non-const, as it was created through new char[N] or allocator.alloc ate(N),
so it seems safe to use const_cast. I could be wrong though. Let me know.
I think some libraries provide only strchr(char *, char), but they should
also have strchr(const char *, char).

Jul 22 '05 #9

"Siemel Naran" <Si*********@RE MOVE.att.net> wrote in message
news:Aw******** ***********@bgt nsc04-news.ops.worldn et.att.net...
"John Harrison" <jo************ *@hotmail.com> wrote in message
news:2inljvFpkd 8vU1@uni-
"Steve" <st*******@hotm ail.com> wrote in message
int GetNewPosition( const std::string& DataStr, const int Spaces)
{
int i = 0; // space counter
char* b = const_cast<char *>(DataStr.c_st r()); // beginning of

string
You also have a completely gratuitous const_cast in your code.
This last point seems fine to me. The original object was obviously
non-const, as it was created through new char[N] or allocator.alloc ate(N),
so it seems safe to use const_cast. I could be wrong though. Let me

know. I think some libraries provide only strchr(char *, char), but they should
also have strchr(const char *, char).


I agree it's safe, but its also unnecessary. By writing const_cast the OP
gives the impression that something tricky is going on in the code, which
isn't the case. Its a completely normal function which can be written
without any casts.

C++ should provide two overloads for strchr

const char* strchr(const char*, int);

and

char* strchr(char*, int);

Because C doesn't have function overloading it can only provide one version
which is the non-const correct

char* strchr(const char*, int);

Maybe that is what persuaded the OP that he needed to use a cast.

john
Jul 22 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
11752
by: Matthew Wilson | last post by:
I'm playing around with genetic algorithms and I want to write a function that mutates an integer by iterating across the bits, and about 1 in 10 times, it should switch a zero to a one, or a one to a zero. I'm not sure how many bits are inside a python integer. The library reference says at least 32. I'm thinking about writing a function that eats integers and poops out lists of bools; and then I can iterate through that, and change...
28
1533
by: rbt | last post by:
Either I'm crazy and I'm missing the obvious here or there is something wrong with this code. Element 5 of this list says it doesn't contain the string 255, when that's *ALL* it contains... why would it think that??? import time ips = for ip in ips: if '255' in ip:
74
5095
by: Michael | last post by:
As if we needed another string reversal question. I have a problem with the following code, that I believe should work. int StringReverse(char* psz) { char *p = psz; char *q = psz + strlen(psz) - 1; while (p < q) {
7
1694
by: Dave Hansen | last post by:
OK, first, I don't often have the time to read this group, so apologies if this is a FAQ, though I couldn't find anything at python.org. Second, this isn't my code. I wouldn't do this. But a colleague did, got an unexpected result, and asked me why. I think I can infer what is occurring, and I was able to find a simple work-around. But I thought I'd ask about it anyway. I've been pushing Python at work for use as a scripting...
6
6060
by: Gustaf Liljegren | last post by:
I ran into this problem today: I got an array with Account objects. I need to iterate through this array to supplement the accounts in the array with more data. But the compiler complains when I try to modify the objects in the array while iterating through it. I marked the bugs in this code: // Loop through all previously added accounts foreach(Account a in a1) // a1 is an ArrayList { // If name and context is the same if(a.Name ==...
2
2167
by: Nick | last post by:
Hi all, Just a quick question. I have a class that exposes a number of fields (which are themselves custom types) through public properties. At run time, I have an object whom I'd like to check, is of same type as one of these fields. Is there a method or technique for iterating through a class's public properties, such as maybe using something from the reflection namespace?
4
2988
by: dustin.getz | last post by:
consider the following working loop where Packet is a subclass of list, with Packet.insert(index, iterable) inserting each item in iterable into Packet at consecutive indexes starting at index. i=0 while(i<len(packet)-4): if packet==Packet("01110"): packet.insert(i, "01111") i+=10 #skip the 5 bits inserted, and skip the 5 bits just checked bc overlap should not trigger insertion
5
1966
by: mikehulluk | last post by:
Ok, Imagine I have a class class C { }; ostream& operator<<(ostream& o, const C& c) { ...}
4
2823
RMWChaos
by: RMWChaos | last post by:
The next episode in the continuing saga of trying to develop a modular, automated DOM create and remove script asks the question, "Where should I put this code?" Alright, here's the story: with a great deal of help from gits, I've developed a DOM creation and deletion script, which can be used in multiple applications. You simply feed the script a JSON list of any size, and the script will create multiple DOM elements with as many attributes...
13
1470
by: kj | last post by:
Is there a special pythonic idiom for iterating over a list (or tuple) two elements at a time? I mean, other than for i in range(0, len(a), 2): frobnicate(a, a) ?
0
9669
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10426
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10207
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10154
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9993
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7537
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5430
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
3713
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2913
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.