Thread overview
How do I use the Tango LineIterator.scan()?
Oct 13, 2008
Robert Kosek
Oct 13, 2008
Robert Kosek
Oct 14, 2008
Robert Kosek
Oct 14, 2008
Alexander Pánek
Oct 14, 2008
Robert Kosek
Oct 14, 2008
Alexander Pánek
October 13, 2008
Hi all,

I'm working on Kata 9 of <codekata.pragprog.com>; thus far there have been interesting problems, but now I need scan functionality.

How does Tango's LineIterator.scan() work?  I'm still very new to D, so I realize this is a template function and object, but I have no idea how to actually use the function in this case.  Can someone give me an exemplary snippet or explanation on how it works?

Thanks,
Robert
October 13, 2008
On Mon, Oct 13, 2008 at 12:13 PM, Robert Kosek <robert.kosek@thewickedflea.com> wrote:
> Hi all,
>
> I'm working on Kata 9 of <codekata.pragprog.com>; thus far there have been interesting problems, but now I need scan functionality.
>
> How does Tango's LineIterator.scan() work?  I'm still very new to D, so I realize this is a template function and object, but I have no idea how to actually use the function in this case.  Can someone give me an exemplary snippet or explanation on how it works?
>
> Thanks,
> Robert
>

LineIterator.scan is really kind of an internal method, I'm not sure
why it's documented.  Most of the public interface to LineIterator is
in its base class, StreamIterator
(http://www.dsource.org/projects/tango/docs/current/tango.text.stream.StreamIterator.html).

There are really two ways to use a StreamIterator: the foreach way and
the next() way.

If you want to get all the lines of a stream, for instance, you can use a foreach loop:

LineIterator lines = new LineIterator(...);
foreach(line; lines) { /* do something with each line */ }

Or, you can use the next() method:

for(auto line = lines.next(); line !is null; line = lines.next())
{ /* do something with each line */ }
October 13, 2008
Jarrett Billingsley wrote:
> LineIterator.scan is really kind of an internal method, I'm not sure
> why it's documented.
>
> There are really two ways to use a StreamIterator: the foreach way and
> the next() way.

That's really helpful, but what I'm trying to figure out how to do is grab data from a plain text file.  Columns are delimited by spaces, but the third column (the last) also contains spaces.  So I'm really searching for a char, an integer, and then a string delimited by a space.

How would I go about doing this without regex?  I know how to use regex, in a general sense, but I don't need it for something this simple.

Thanks for your time Jarrett.

Robert
October 13, 2008
On Mon, Oct 13, 2008 at 1:33 PM, Robert Kosek <robert.kosek@thewickedflea.com> wrote:
> Jarrett Billingsley wrote:
>>
>> LineIterator.scan is really kind of an internal method, I'm not sure why it's documented.
>
>>
>>
>> There are really two ways to use a StreamIterator: the foreach way and
>> the next() way.
>
> That's really helpful, but what I'm trying to figure out how to do is grab data from a plain text file.  Columns are delimited by spaces, but the third column (the last) also contains spaces.  So I'm really searching for a char, an integer, and then a string delimited by a space.
>
> How would I go about doing this without regex?  I know how to use regex, in a general sense, but I don't need it for something this simple.
>
> Thanks for your time Jarrett.
>
> Robert
>

In that case, once you have the line that you got from the LineIterator, you can split it up using methods found in tango.text.Util.  You can use the locate() function to find the first space.  You can then set it to start at a certain position, so that you can get the position of the second space after it.

import tango.text.Util;
...
// using line as the line of text.
auto firstSpace = line.locate(' '); // syntactic sugar for locate(line, ' ')
auto secondSpace = line.locate(' ', firstSpace + 1);
auto firstCol = line[0 .. firstSpace];
auto secondCol = line[firstSpace + 1 .. secondSpace];
auto thirdCol = line[secondSpace + 1 .. $]; // $ means line.length

// now you can convert the columns as you please
October 14, 2008
Jarrett Billingsley wrote:
> You can use the locate() function to find the first
> space.  You can then set it to start at a certain position, so that
> you can get the position of the second space after it.

Thank you very much Jarrett, this was just what I needed.  I got the whole thing working now. :)

Thanks,
Robert
October 14, 2008
Jarrett Billingsley wrote:
> import tango.text.Util;
> ...
> // using line as the line of text.
> auto firstSpace = line.locate(' '); // syntactic sugar for locate(line, ' ')
> auto secondSpace = line.locate(' ', firstSpace + 1);
> auto firstCol = line[0 .. firstSpace];
> auto secondCol = line[firstSpace + 1 .. secondSpace];
> auto thirdCol = line[secondSpace + 1 .. $]; // $ means line.length
> 
> // now you can convert the columns as you please

auto columns = line.split(" ");
auto firstCol = columns[0];
auto secondCol = columns[1];
// ... that’s a tad shorter. :P
October 14, 2008
Alexander Pánek wrote:
> auto columns = line.split(" ");
> auto firstCol = columns[0];
> auto secondCol = columns[1];
> // ... that’s a tad shorter. :P

Quite so, Alexander, and that's what I switched to in my code.  I refactored what I had and switched to commas, just in case someone uses whitespace to pad things. ;-)

And if you know what exercise 9 is on the site, you have variable input.  Which does make it a fun experience.  My constructor just takes the line and parses it, so it's quite convenient.

I wound up with:
> this(char[] line) {
>   auto parts = split(line, ",");
>
>   this.sku = parts[0][0];
>   this.price = Integer.parse(parts[1]);
>   this.hasSpecial = parts.length >= 3;
>
>   if(this.hasSpecial) {
>     auto parts2  = split(parts[2], " for ");
>     this.s_qty   = Integer.parse(parts2[0]);
>     this.s_price = Integer.parse(parts2[1]);
>   }
> }

And I use the LineInput object in the parent class to read and iterate through the lines.

I must say that I like D and the Tango library. =)

Cheers,
Robert
October 14, 2008
On Mon, Oct 13, 2008 at 10:28 PM, Alexander Pánek <alexander.panek@brainsware.org> wrote:
> Jarrett Billingsley wrote:
>>
>> import tango.text.Util;
>> ...
>> // using line as the line of text.
>> auto firstSpace = line.locate(' '); // syntactic sugar for locate(line, '
>> ')
>> auto secondSpace = line.locate(' ', firstSpace + 1);
>> auto firstCol = line[0 .. firstSpace];
>> auto secondCol = line[firstSpace + 1 .. secondSpace];
>> auto thirdCol = line[secondSpace + 1 .. $]; // $ means line.length
>>
>> // now you can convert the columns as you please
>
> auto columns = line.split(" ");
> auto firstCol = columns[0];
> auto secondCol = columns[1];
> // ... that's a tad shorter. :P

The third column can have spaces.  This will split on them too.  Not
to mention line.split() will allocate a new array every time it's
called ;)
October 14, 2008
Jarrett Billingsley wrote:
> On Mon, Oct 13, 2008 at 10:28 PM, Alexander Pánek
> <alexander.panek@brainsware.org> wrote:
>> Jarrett Billingsley wrote:
>>> import tango.text.Util;
>>> ...
>>> // using line as the line of text.
>>> auto firstSpace = line.locate(' '); // syntactic sugar for locate(line, '
>>> ')
>>> auto secondSpace = line.locate(' ', firstSpace + 1);
>>> auto firstCol = line[0 .. firstSpace];
>>> auto secondCol = line[firstSpace + 1 .. secondSpace];
>>> auto thirdCol = line[secondSpace + 1 .. $]; // $ means line.length
>>>
>>> // now you can convert the columns as you please
>> auto columns = line.split(" ");
>> auto firstCol = columns[0];
>> auto secondCol = columns[1];
>> // ... that's a tad shorter. :P
> 
> The third column can have spaces.  This will split on them too.  Not
> to mention line.split() will allocate a new array every time it's
> called ;)

Nittypickybulubulub! It is shorter in code, qed. ;P