std::string::npos always < std::string::size() ?

C

Christopher Pisz

Is std::string::npos always going to be less than any std::string 's size()?

I am trying to handle a replacement of all occurances of a substr, in which
the replacement also contains the substr. Yick. All I could come up with is:

#include <string>

int main()
{
std::string text;
text = "\nThis is a test line with newlines\n<-here and \n<-here and
\n\n<-two here";

// Format the text
std::string formattedText(text);

// Change every occurrance of "\n" to "\r\n"
std::string::size_type index = 0;

do
{
index = formattedText.find('\n', index);
if( index != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}
} while( index < formattedText.size() );

// debugging contents of formattedText here

return 0;
}

However, it depends on std::string::npos always being less than the size of
the string and I am not certain whether that is safe or not.
 
D

Dreamlax

Is std::string::npos always going to be less than any std::string 's size()?

I am trying to handle a replacement of all occurances of a substr, in which
the replacement also contains the substr. Yick. All I could come up with is:

#include <string>

int main()
{
std::string text;
text = "\nThis is a test line with newlines\n<-here and \n<-here and
\n\n<-two here";

// Format the text
std::string formattedText(text);

// Change every occurrance of "\n" to "\r\n"
std::string::size_type index = 0;

do
{
index = formattedText.find('\n', index);
if( index != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}
} while( index < formattedText.size() );

// debugging contents of formattedText here

return 0;

}

However, it depends on std::string::npos always being less than the size of
the string and I am not certain whether that is safe or not.

I know this is a horrible solution, but what about something along the
lines copying the contents of the string to another string?


int i;

for (i = 0; i < string1.size(); i++)
{
if (string1 == '\n') string2 += "\r\n";
else string2 += string1;
}


It's slow and bloated it does the job in a straightforward way.
 
A

Abhishek Padmanabh

Is std::string::npos always going to be less than any std::string 's size()?

I am trying to handle a replacement of all occurances of a substr, in which
the replacement also contains the substr. Yick. All I could come up with is:

#include <string>

int main()
{
   std::string text;
   text = "\nThis is a test line with newlines\n<-here and \n<-here and
\n\n<-two here";

   // Format the text
   std::string formattedText(text);

   // Change every occurrance of "\n" to "\r\n"
   std::string::size_type index = 0;

   do
   {
      index = formattedText.find('\n', index);
      if( index != std::string::npos )
      {
         formattedText.insert(index, "\r");
         index += 2;
      }
   } while( index < formattedText.size() );

   // debugging contents of formattedText here

   return 0;

}

However, it depends on std::string::npos always being less than the size of
the string and I am not certain whether that is safe or not.

It is ok/safe. An std::string cannot have a length() (since it is
std::string, size()) greater than std::string::npos. So, your code
should be perfectly fine, it will always exit the do-while when all
instances of '\n' have been dealt with.
 
A

Abhishek Padmanabh

It is ok/safe. An std::string cannot have a length() (since it is
std::string, size()) greater than std::string::npos. So, your code
should be perfectly fine, it will always exit the do-while when all
instances of '\n' have been dealt with.- Hide quoted text -

- Show quoted text -

Ideally, you should handle the length_error exception.
 
J

Jim Langston

Christopher said:
Is std::string::npos always going to be less than any std::string 's
size()?

Actually, the other way around. std::string::npos is always going to be
greater than sny std::string's size.
I am trying to handle a replacement of all occurances of a substr, in
which the replacement also contains the substr. Yick. All I could
come up with is:
#include <string>

int main()
{
std::string text;
text = "\nThis is a test line with newlines\n<-here and \n<-here and
\n\n<-two here";

// Format the text
std::string formattedText(text);

// Change every occurrance of "\n" to "\r\n"
std::string::size_type index = 0;

do
{
index = formattedText.find('\n', index);
if( index != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}
} while( index < formattedText.size() );

// debugging contents of formattedText here

return 0;
}

However, it depends on std::string::npos always being less than the
size of the string and I am not certain whether that is safe or not.


Your code is perfectly fine, however, your while statment can simply be
changed to:

} while ( index != std::string::npos );

And you could even simplify it a bit by rearranging it.

index = 0;
while ( ( index = formattedText.find('n', index ) != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}

Now you don't need the if statmeent and to me it is cleaner code.
 
J

James Kanze

Is std::string::npos always going to be less than any
std::string 's size()?

It's always going to be greater.
I am trying to handle a replacement of all occurances of a
substr, in which the replacement also contains the substr.
Yick. All I could come up with is:
#include <string>
int main()
{
std::string text;
text = "\nThis is a test line with newlines\n<-here and \n<-here and
\n\n<-two here";
// Format the text
std::string formattedText(text);
// Change every occurrance of "\n" to "\r\n"
std::string::size_type index = 0;
do
{
index = formattedText.find('\n', index);
if( index != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}
} while( index < formattedText.size() );
// debugging contents of formattedText here
return 0;
}
However, it depends on std::string::npos always being less
than the size of the string and I am not certain whether that
is safe or not.

Your code should work, although I'd definitely use a while or a
for, rather than a do...while:

for ( size_t pos = text.find( '\n' ) ;
pos != std::string::npos ;
pos = text.find( '\n', pos + 2 ) ) {
text.insert( pos, '\r' ) ;
}

But generally, I'd rather not do this sort of thing in place.
Something more like:

std::string
convertToDos( std::string const& source )
{
std::string result ;
for ( std::string::const_iterator it = source.begin() ;
it != source.end() ;
++ it ) {
switch (*it) {
case '\n' :
result += "\r\n" ;
break ;

default :
result += *it ;
break ;
}
}
return result ;
}

This seems a lot cleaner to me, despite having more lines of
code, and is probably faster as well (less copying). If the
strings are very long, and performance is still a problem, you
can add the following after the definition of result:

result.reserve( source.size()
+ std::count( source.begin(), source.end(),
'\n' ) ;

. Unless the strings are very long, however, it probably won't
matter.)
 
J

James Kanze

[...]
And you could even simplify it a bit by rearranging it.
index = 0;
while ( ( index = formattedText.find('n', index ) != std::string::npos )
{
formattedText.insert(index, "\r");
index += 2;
}

Which has a nested assignment guaranteed to make the code more
difficult to read. As posted elsewhere, I'd do it with a for:

for ( size_t pos = formattedText.find( '\n' ) ;
pos != std::string::npos ;
pos = formattedText.find( '\n', pos + 2 ) ) {
formattedText.insert( pos, '\r' ) ;
}

Everything where a reader would expect to find it.
Now you don't need the if statmeent and to me it is cleaner code.

An assignment nested in a condition will never be considered
clean code. A statement should do one, and only one thing.
 
J

Jim Langston

James said:
[...]
And you could even simplify it a bit by rearranging it.
index = 0;
while ( ( index = formattedText.find('n', index ) !=
std::string::npos ) {
formattedText.insert(index, "\r");
index += 2;
}

Which has a nested assignment guaranteed to make the code more
difficult to read. As posted elsewhere, I'd do it with a for:

for ( size_t pos = formattedText.find( '\n' ) ;
pos != std::string::npos ;
pos = formattedText.find( '\n', pos + 2 ) ) {
formattedText.insert( pos, '\r' ) ;
}

Everything where a reader would expect to find it.

I would like others opionion on which they consider cleaner code.

I do ( var = something ) == something
all the time, and have always considered it clean.

Opinions?
 
R

Ron AF Greve

Hi,

Use that all the time too, nothing wrong with it, in my opinion. But then
again every developer seems to have his/her own rules :)


Regards, Ron AF Greve

http://www.InformationSuperHighway.eu

Jim Langston said:
James said:
[...]
And you could even simplify it a bit by rearranging it.
index = 0;
while ( ( index = formattedText.find('n', index ) !=
std::string::npos ) {
formattedText.insert(index, "\r");
index += 2;
}

Which has a nested assignment guaranteed to make the code more
difficult to read. As posted elsewhere, I'd do it with a for:

for ( size_t pos = formattedText.find( '\n' ) ;
pos != std::string::npos ;
pos = formattedText.find( '\n', pos + 2 ) ) {
formattedText.insert( pos, '\r' ) ;
}

Everything where a reader would expect to find it.

I would like others opionion on which they consider cleaner code.

I do ( var = something ) == something
all the time, and have always considered it clean.

Opinions?
An assignment nested in a condition will never be considered
clean code. A statement should do one, and only one thing.
 
J

James Kanze

James said:
[...]
And you could even simplify it a bit by rearranging it.
index = 0;
while ( ( index = formattedText.find('n', index ) !=
std::string::npos ) {
formattedText.insert(index, "\r");
index += 2;
}
Which has a nested assignment guaranteed to make the code
more difficult to read. As posted elsewhere, I'd do it with
a for:
for ( size_t pos = formattedText.find( '\n' ) ;
pos != std::string::npos ;
pos = formattedText.find( '\n', pos + 2 ) ) {
formattedText.insert( pos, '\r' ) ;
}
Everything where a reader would expect to find it.
I would like others opionion on which they consider cleaner code.
I do ( var = something ) == something
all the time, and have always considered it clean.
Opinions?

In addition to opinions, there are measurable differences in
readability. When scanning the code rapidly, "if" or "while"
means flow control, not state change. Doing too many things in
a single statement leads to obfuscation.

Obviously, it's not an absolute rule, and must be weighed
against other "obfuscations" that obeying it might introduce.
And there are idioms so ubiquious that they are recognized
despite breaking the rule: I write things like:
while ( std::getline( source, line ) ) ...
, for example, even though it violates the rule, because it is
so ubiquious that doing it any other way raises questions. I
would hope, however, that we're past the time when people
thought it clever to put the entire function in a single
condition---things like:
while ( *p ++ = *q ++ );
or even
while ( (*p ++ = *q ++) != 0 );
(The first is drawn from the original K&R, and even back then,
the authors expressed some doubts as to its advisability.)

In this particular case, there's absolutely no reason to "hide"
the update of index. Especially as you also have a specific
update at the end of the while, where people would normally look
for it: your loop looks like a classical "while" (which I would
normally write as a for), with update of the control variable at
the end of the loop, and then you sneek in an additional update
in the conditional expression.

In an ideal world, to find where a variable is being modified,
it would be sufficient to scan down the file looking at the
first token in each line. Obviously, that ideal isn't really
attainable, but you shouldn't have to search into the middle of
a complicated expression either.
 
J

Jerry Coffin

[ ... ]
I do ( var = something ) == something
all the time, and have always considered it clean.

I don't see much reason to do it in the case of the code earlier in this
thread, but in some cases, I think this is exactly the correct thing to
do.

Just for one example, I believe when writing code to open a file using
fopen, the correct way to do it is something like:

if (NULL==(file=fopen(whatever, "r")))
// handle error

Getting into the habit of coding this way assures that a problem with
opening the file will always be handled. Code that separates opening and
testing:

file = fopen(whatever, "r");

if ( file == NULL)
// handle error

....makes some types of errors much easier. One is leaving out the
testing code entirely. The other is accidentally inserting something
between opening and testing that depends on the file having been opened
correctly. Both are obviously errors, but are also easy to miss until
the code is tested with a file that can't be opened.
 
J

James Kanze

[ ... ]
I do ( var = something ) == something
all the time, and have always considered it clean.
I don't see much reason to do it in the case of the code
earlier in this thread, but in some cases, I think this is
exactly the correct thing to do.
Just for one example, I believe when writing code to open a
file using fopen, the correct way to do it is something like:
if (NULL==(file=fopen(whatever, "r")))
// handle error
Getting into the habit of coding this way assures that a
problem with opening the file will always be handled. Code
that separates opening and testing:
file = fopen(whatever, "r");
if ( file == NULL)
// handle error
...makes some types of errors much easier. One is leaving out
the testing code entirely. The other is accidentally inserting
something between opening and testing that depends on the file
having been opened correctly. Both are obviously errors, but
are also easy to miss until the code is tested with a file
that can't be opened.

I've not found this to be a problem, and do generally do the
open separately. Especially with [io]fstream:
std::ifstream input( filename.c_str() ) ;
if ( ! input.is_open() ) ...
If there is an exception to my rule, however, it is when the
return value contains an error indicator---especially, if it is
only an error indicator---and the function has serious side
effects otherwise. Personally, I don't nest the assignment if
the return value is saved, but I don't have too much problem
with people who write things like:
while ( (length = read( fd, buffer, bufSize )) > 0 ) {
}
, and of course, I do write things like:
while ( std::getline( input, line ) ) {
}
which is really fairly similar, except that the additional state
is saved in the iostream object (i.e. failbit, eofbit, etc.),
and not in a variable that I explicitly assign. Ideally, one
would like for a condition never to have any side effects, but
sometimes, the cure is worse than the disease (although the only
problem I have with something like:

std::getline( input, line ) ;
while ( input ) {
//...
std::getline( input, line ) ;
}

is that it isn't idiomatic. Independantly of any other
advantages or disadvantages, an experienced C++ programmer who
sees it will ask himself why the idiomatic form wasn't used.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top