www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How do I use the Tango LineIterator.scan()?

reply Robert Kosek <robert.kosek thewickedflea.com> writes:
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
Oct 13 2008
parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
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 */ }
Oct 13 2008
parent reply Robert Kosek <robert.kosek thewickedflea.com> writes:
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
Oct 13 2008
parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
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
Oct 13 2008
next sibling parent Robert Kosek <robert.kosek thewickedflea.com> writes:
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
Oct 13 2008
prev sibling parent reply =?UTF-8?B?QWxleGFuZGVyIFDDoW5law==?= writes:
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
Oct 13 2008
next sibling parent Robert Kosek <robert.kosek thewickedflea.com> writes:
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
Oct 14 2008
prev sibling parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Mon, Oct 13, 2008 at 10:28 PM, Alexander P=E1nek
<alexander.panek brainsware.org> wrote:
 Jarrett Billingsley wrote:
 import tango.text.Util;
 ...
 // using line as the line of text.
 auto firstSpace =3D line.locate(' '); // syntactic sugar for locate(line=
, '
 ')
 auto secondSpace =3D line.locate(' ', firstSpace + 1);
 auto firstCol =3D line[0 .. firstSpace];
 auto secondCol =3D line[firstSpace + 1 .. secondSpace];
 auto thirdCol =3D line[secondSpace + 1 .. $]; // $ means line.length

 // now you can convert the columns as you please
auto columns =3D line.split(" "); auto firstCol =3D columns[0]; auto secondCol =3D 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 ;)
Oct 14 2008
parent =?UTF-8?B?QWxleGFuZGVyIFDDoW5law==?= writes:
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
Oct 14 2008