Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Simple regex / split example?

137 views
Skip to first unread message

John Harrison

unread,
Mar 20, 2004, 6:34:25 AM3/20/04
to

"Ian.H" <i...@WINDOZEdigiserv.net> wrote in message
news:pan.2004.03.20....@hybris.digiserv.net...
> Hi all,
>
> I've spent some time Googling, looking at man pages and Borland C++
> Builder's help files and found nothing that's got me underway on this.
>
> I'm looking for either a simple example, or a pointer for either a simple
> regex or "split" call on a string if anyone wishes to share =)
>
> C / C++ is not my "native" language but it's proving fun learning, but
> this one's got me stumped.
>
> I need to reverse an IP address in sections, such as:
>
>
> 127.0.0.1 -> 1.0.0.127
>

Here's a simple technique, it relies of the fact that you can specify the
end of line character in getline.

#include <string>
#include <sstream>
using namespace std;

string ip = "127.0.0.1";
istringstream input_buffer(ip);
string a, b, c, d;
getline(input_buffer, a, '.');
getline(input_buffer, b, '.');
getline(input_buffer, c, '.');
getline(input_buffer, d, '.');
ostringstream output_buffer;
output_buffer << d << '.' << c << '.' << b << '.' << a;
string reversed_ip = output_buffer.str();

(untested code)

Not as terse a Perl admittedly, but since when was terseness an advantage in
a programming language?

john


Siemel Naran

unread,
Mar 20, 2004, 7:04:14 PM3/20/04
to
"John Harrison" <john_an...@hotmail.com> wrote in message
news:c3ha7t$26kbhb$1@ID-

> "Ian.H" <i...@WINDOZEdigiserv.net> wrote in message

> Here's a simple technique, it relies of the fact that you can specify the


> end of line character in getline.
>
> #include <string>
> #include <sstream>
> using namespace std;
>
> string ip = "127.0.0.1";
> istringstream input_buffer(ip);
> string a, b, c, d;
> getline(input_buffer, a, '.');
> getline(input_buffer, b, '.');
> getline(input_buffer, c, '.');
> getline(input_buffer, d, '.');
> ostringstream output_buffer;
> output_buffer << d << '.' << c << '.' << b << '.' << a;
> string reversed_ip = output_buffer.str();

I don't know much about internet stuff, but could we have other than 4
entries like a.b.c.d.e or a.b.c?


Siemel Naran

unread,
Mar 20, 2004, 7:31:26 PM3/20/04
to
"Ian.H" <i...@WINDOZEdigiserv.net> wrote in message

> I've spent some time Googling, looking at man pages and Borland C++


> Builder's help files and found nothing that's got me underway on this.
>
> I'm looking for either a simple example, or a pointer for either a simple
> regex or "split" call on a string if anyone wishes to share =)

Too bad we don't have a split function in the standard. I wrote this
function some time ago:

template <class Delim, class charT, class traits, class OutIter>
OutIter split(
const std::basic_string<charT,traits>&,
OutIter,
bool many_delimeters,
const Delim& = Delim()
);

export
template <class Delim, class charT, class traits, class OutIter>
OutIter enhanced::split(
const std::basic_string<charT,traits>& in,
OutIter out,
bool many_delimeters,
const Delim& delim
)
{
typedef std::string::const_iterator Iter;
const Iter end = in.end();
Iter iter = in.begin();
while (true)
{
if (many_delimeters)
{
for ( ; iter!=end && delim(*iter); ++iter) ;
}
if (iter==end) break;
const Iter begin = iter;
for ( ; iter!=end && !delim(*iter); ++iter) ;
*out = std::string(begin,iter);
++out;
if (iter==end) break;
++iter;
}
return out;
}


> C / C++ is not my "native" language but it's proving fun learning, but
> this one's got me stumped.
>
> I need to reverse an IP address in sections, such as:
>
>
> 127.0.0.1 -> 1.0.0.127
>
>

> In Perl, I'd use 1 of 2 methods (method 1 preferable):
>
>
> my $ip = '127.0.0.1';
> my @array = split /\./, $ip;
> my $rev_ip = join '.', reverse @array;
>
> or
>
> my $ip = '127.0.0.1';
> $ip =~ /^([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}$/
> my $rev_ip = "$4.$3.$2.$1";
>
>
> This seems such a simple piece of code / request but alas I can't seem to
> understand the pcreposix.h calls enough to get this working. If anyone has
> any info / advice of examples of how I might go about this, it'd be much
> appreciated =)

std::string ip("127.0.0.1");
std::list<std::string> array;
enhanced::split(ip, std::back_inserter(array), false, isdot); // calls
push_back(127), push_back(0), push_back(0), push_back(1)
std::reverse(array);
// oops: i didn't write a combine function!

where

bool isdot(char c) { return c=='.'; }

We can make it faster quite easily by avoiding the call to reverse. When we
split the original array, we'll place the elements into the array using
push_front, so 127.0.0.1 invokes push_front(127), push_front(0),
push_front(0), push_front(1).

std::string ip("127.0.0.1");
std::list<std::string> array;
enhanced::split(ip, std::front_inserter(array), false, isdot);
// oops: i didn't write a combine function!

As for printing the reversed string, I think this would work

std::copy(array.begin(), array.end(), std::ostream_iterator(std::cout,
'.'));

But maybe it will print an extra dot at the end.

You can also reverse in place. Reverse the entire string. Then locate the
words seperated by dots, and reverse in place.

std::string ip("127.0.0.1");
std::reverse(ip);
typedef std::string::iterator Iter;
Iter wordbegin = ip.begin();
const end = ip.end();
while (wordbegin != end) {
const Iter wordend = find(wordbegin, end, '.');
std::reverse(wordbegin, wordend);
wordbegin = wordend;
}


David Harmon

unread,
Mar 20, 2004, 9:38:23 PM3/20/04
to
On Sat, 20 Mar 2004 11:25:50 GMT in comp.lang.c++, "Ian.H"
<i...@WINDOZEdigiserv.net> wrote,
>Hi all,

>
>I've spent some time Googling, looking at man pages and Borland C++
>Builder's help files and found nothing that's got me underway on this.
>
>I'm looking for either a simple example, or a pointer for either a simple
>regex or "split" call on a string if anyone wishes to share =)

My favorite regex library at present is the one from
http://www.boost.org/

For a simple splitter I just use

template < class OI >
OI split(const std::string & input, const std::string & delims, OI dest)
{
std::string::size_type first = 0, last = 0;
while (first < input.size() && last != std::string::npos) {
last = input.find_first_of(delims, first);
*dest++ = input.substr(first, last - first);
first = last+1;
}
return dest;
}

>In Perl, I'd use 1 of 2 methods (method 1 preferable):
>
> my $ip = '127.0.0.1';
> my @array = split /\./, $ip;
> my $rev_ip = join '.', reverse @array;

std::string ip = "127.0.0.1";
std::vector<string> array;
split(ip, ".", back_inserter(array)); // using above split
std::ostringstream rev_ip;
std::copy(array.rbegin(), array.rend(),
ostream_iterator<string>(rev_ip, "."));
return rev_ip.str();

>or
>
> my $ip = '127.0.0.1';
> $ip =~ /^([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}$/
> my $rev_ip = "$4.$3.$2.$1";

#include "boost/regex.hpp"

string ip = "127.0.0.1";
static const boost::regex rexp(
"^([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}\.([0-9]){1,3}$" );
boost::cmatch tokens;
if (boost::regex_match(ip, tokens, rexp)) {
string rev_ip = tokens.str(4) + "." + tokens.str(3) + "."
+ tokens.str(2) + "." + tokens.str(1);
}

Siemel Naran

unread,
Mar 21, 2004, 11:50:44 PM3/21/04
to
"Ian.H" <i...@WINDOZEdigiserv.net> wrote in message
> On Sun, 21 Mar 2004 00:31:26 +0000, Siemel Naran wrote:

> Hi Seimel..

Hi.


> > template <class Delim, class charT, class traits, class OutIter>
> > OutIter enhanced::split(
> > const std::basic_string<charT,traits>& in,
> > OutIter out,
> > bool many_delimeters,
> > const Delim& delim
> > )
> > {
> > typedef std::string::const_iterator Iter;
> > const Iter end = in.end();
> > Iter iter = in.begin();
> > while (true)
> > {
> > if (many_delimeters)
> > {
> > for ( ; iter!=end && delim(*iter); ++iter) ;
> > }
> > if (iter==end) break;
> > const Iter begin = iter;
> > for ( ; iter!=end && !delim(*iter); ++iter) ;
> > *out = std::string(begin,iter);
> > ++out;
> > if (iter==end) break;
> > ++iter;
> > }
> > return out;
> > }
>
>

> This looks very useful. Not sure I understand all of it.. but can follow
> the majority. I think it's the <...> (template) part that's a little
> confusing.. $DAY_JOB revolves around PHP majoritively (which is
> extremely sloppy internally compared to C / C++).. but I'll read to
> understand the above in more detail =)

PHP sounds fine from your posted snippet; not too familiar with it. Will
try to explain. I didn't put enough comments, and we especially need
comments for Delim to explain the expected traits.

> > template <class Delim, class charT, class traits, class OutIter>
> > OutIter enhanced::split(

It's a generic splitter function. std::string is a specialization of
std::basic_string<char, std::char_traits<char>>, or in other words
charT==char and traits==std::char_traits<char>. We could use the same
function of wide-char strings with charT==wchar_t, or any user modified
traits such as one to compare strings without case sensitivity. The first
argument Delim is a class that tells whether a char is a delimeter, and the
expected trait it to either pass in a pointer to a function like
std::isspace or an instance of a new class that defines a bool
operator()(charT) const. The last template argument OutIter is where to
store each split word, and it will often be a std::back_insert_iterator
which is an object that calls push_back on a fixed container. Any clearer?


> This again looks great.. and again I'll need to google some more on
> <lists> to help me understand things a little better too (I hate
> implementing code I don't understand myself).

std::list and std::vector are just containers. You mention you use Borland,
and you can maybe find documentation on it in the help. Or try the
internet. std::list and std::deque support push_front though it could be
faster for list, but std::vector does not. Anyway, you can push_back
elements into a vector, and iteration using reverse iterators as in David's
post, but I didn't think of this solution.


0 new messages