val val - 2 years ago 83
C++ Question

Iterate over string fragments

I've got lua path, e.g.:

"/home/user/?.lua;/home/test/?/init.lua;./lua"


I want to iterate over every fragment (
/home/user/?.lua
,
/home/test/?/init.lua
and
./lua
in example). My attempt doesn't work correctly for some reasons:

size_t begin = 0;
size_t next = searchpath.find_first_of(";", 0);
do
{
if (next == std::string::npos)
next = searchpath.length();
std::string prefix = searchpath.substr(begin, next);
std::cout << "Trying: " << prefix << "\n";
begin = next + 1;
next = searchpath.find_first_of(";", begin);
} while (begin < (int)searchpath.length());


Output:

Trying: /home/v/.luarocks/share/lua/5.2/?.lua
Trying: /home/v/.luarocks/share/lua/5.2/?/init.lua;/usr/share/lua/5.2/?.lua;/usr/share/l
Trying: /usr/share/lua/5.2/?.lua;/usr/share/lua/5.2/?/init.lua;/usr/local/share/lua/5.2/?.lua;/usr/local/share/lu
Trying: /usr/share/lua/5.2/?/init.lua;/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/loca
Trying: /usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua;/home/v/.lua/libs/?.lua;/hom
Trying: /usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua;/home/v/.lua/libs/?.lua;/home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: /usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua;/home/v/.lua/libs/?.lua;/home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: /usr/local/lib/lua/5.2/?/init.lua;./?.lua;/home/v/.lua/libs/?.lua;/home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: ./?.lua;/home/v/.lua/libs/?.lua;/home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: /home/v/.lua/libs/?.lua;/home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: /home/v/.lua/libs/?.lua;./lib/?.lua;./lib/?/init.lua
Trying: ./lib/?.lua;./lib/?/init.lua


Can you explain me, please, what is wrong with my code and what is correct way?

Answer Source

The problem is:

    std::string prefix = searchpath.substr(begin, next);

std::string::substr takes offset + count arguments, not start + end arguments.

You need:

    std::string prefix = searchpath.substr(begin, next-begin);

So in full:

#include <iostream>
#include <string>

int main()
{
    std::string searchpath = "a;b;c";
    size_t begin = 0;
    size_t next = searchpath.find_first_of(";", 0);
    do
    {
        if (next == std::string::npos)
            next = searchpath.length();
        std::string prefix = searchpath.substr(begin, next-begin);
        std::cout << "Trying: " << prefix << "\n";
        begin = next + 1;
        next = searchpath.find_first_of(";", begin);
    } while (begin < (int)searchpath.length());
}

(Note, that is what your question should have looked like. A complete program.)

I would actually write as:

#include <iostream>
#include <string>

int main()
{
    std::string searchpath = "a;b;c";
    for (size_t begin = 0, next; begin < searchpath.length(); begin = next+1)
    {
        next = searchpath.find(';', begin);
        if (next == std::string::npos)
            next = searchpath.length();
        std::string prefix = searchpath.substr(begin, next-begin);
        std::cout << "Trying: " << prefix << "\n";
    }
}

Which has less repetition, localizes begin and next to the loop, uses find not find_first_of, and doesn't have an unnecessary cast.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download