views:

2090

answers:

8

Hi, I am trying to figure out the best way to parse this comma delimited text file. Here is an excerpt:

bldgA, fred, lunch
bldgA, sally, supper
bldgB, bob, parking lot
bldgB, frank, rooftop
...

What I am trying to do is read "bldgA" and then I want the person (2nd column), "fred" for example. But I don't want to parse the file looking for "fred" because fred may not be there next time whereas bldgA always will be. I want to read the text file, see that I am on bldgA, and read the next item in my list which is fred. After that I want to test if it is fred, sally, etc.and print out the third column. I know this might be easier with a database but seems to be a bit of overhead for a small text file just so I can name columns. Before I resorted to Access or something small, I thought I'd try stackoverflow. Here is what I have:

string BuildingFile = Server.MapPath("buildings.txt");
StreamReader FileStreamReader;

FileStreamReader = File.OpenText(BuildingFile);

while (FileStreamReader.Peek() != -1)
{   
    string[] words;
    words = FileStreamReader.ReadLine().Split(',');

    foreach (string word in words)
    {
        if (word == "bldgA")
        {
            //but since word is only on "bldgA" 
            //how can I get the next item in the list which 
            //is on the same line?

            //print out the name of the person and then the duty
        }
        if (word == "bldgB")
        {
            //same as A   
        }
    }

}
FileStreamReader.Close();

My final output would be

"You are in bldgA and your name is fred and your duty is lunch"

Thank you.

A: 

Use a state machine, basically. Have a variable called "building", and store the building name in there when you encounter one. Then have cases for people's names which operate on that building.

Your explanation isn't very clear, and your example is strange. If you can reword that I could most likely provide a better answer.

strager
+2  A: 

If you know that the file will ALWAYS be formatted correctly, you could do something like (using your code, assuming the language is C#):

String MyLocation = System.Net.Dns.GetHostName();

string MachineFile = Server.MapPath("buildings.txt");
StreamReader FileStreamReader;

FileStreamReader = File.OpenText(MachineFile);

while (FileStreamReader.Peek() != -1)
{   
    string[] words;
    words = FileStreamReader.ReadLine().Split(',');

    if(words.Length == 3)
    {
        StringBuilder output = new StringBUilder;
        output.Append("You are in ");
        output.Append(words[0]);
        output.Append(" and your name is ");
        output.Append(words[1]);
        output.Append(" and your duty is ");
        output.AppendLine(words[2]);
    }
}
FileStreamReader.Close();
phsr
+1  A: 

Instead of using a foreach loop, why don't you do something like this:

words = FileStreamReader.ReadLine().Split(',', 3);
StringBuilder output = new StringBuilder();
if (words.Length >= 1)
{
    output.AppendFormat("You are in {0}", words[0]);
    if (words.Length >= 2)
    {
        output.AppendFormat(" and your name is {0}", words[1]);
        if (words.Length >= 3)
        {
            output.AppendFormat(" and your duty is {0}", words[2]);
        }
    }
}
Console.WriteLine(output.ToString()); // or write wherever else you want your output to go
Trent
+2  A: 

Use the FileHelpers library. It allows you to create classes to store your data and provides an easy way to then parse a data store (including csv) to fill those classes.

But, as you've suggested, this seems like a job for a database. I'd consider SQLite.

MattyT
+1  A: 

An object db is better for your solution. You can use db4o, very good open- source one.

But if you insist on using comma delimited file, take a look at this CsvReader, you can use it to read the file.

Sunny
A: 

I think that your excerpt is intended as so:

bldgA,fred,lunch
bldgA,sally,supper
bldgB,bob,parking lot
bldgB,frank,rooftop

The steps to get your desired output:

  • read one line
  • split the line along commata
  • format your desired output with the parts returned from the split function

A split function is often part of a regex library.

In Common Lisp, this could be written like this:

(defun show-people-status (filename)
  (with-open-file (input-stream filename)
    (do ((line (read-line input-stream nil nil)
               (read-line input-stream nil nil)))
        ((null line) t)
      (apply #'format t "You are in ~a, your name is ~a, and your duty is ~a.~%"
             (cl-ppcre:split "," line)))))

In Perl, you could use something like this:

#!/usr/bin/perl -w
use strict;

use Tie::File;

tie (@data, 'Tie::File', $ARGV[0]);

foreach (@data) {
    (my $Building, my $Name, my $Duty) = split (/,/);
    print "You are in $Building, your name is $Name, and your duty is $Duty."; };

Note that the Perl version is intended as a standalone script, while the CL version shows a function to be used from the runtime. There is no input checking in either.

Svante
perl -F, -ane'my ($bldg, $name, $duty) = @F; print qq(name: $name, duty: $duty\n) if $bldg =~ /bldg[AB]/' buildings.txt
J.F. Sebastian
A: 

In pseudo-code:

#!/usr/bin/env python
import csv

with open('buildings.txt') as csvfile:
    for building, name, duty in csv.reader(csvfile):
        print("You are in %(building)s"
              " and your name is %(name)s"
              " and your duty is %(duty)s" % vars())
J.F. Sebastian
A: 

Forgive me for programming it this way, but I think it may solves your problem.

The only assumption that I made is that somewhere in buildings.txt there's a column named "bldgA" and there's always 2 more columns to its right and those are the data you want.

private static int GetIndexOf(string hay, string needle, char delimiter)
{
    return Array.FindIndex<string>(hay.Split(delimiter), delegate(string match)
    {
        if (needle.Equals(match.Trim()))
            return true;
        else
            return false;
    });
}

static void Main(string[] args)
{
    StreamReader sr = new StreamReader(Server.MapPath("buildings.txt"));
    using (sr)
    {
        for (string line; null != (line = sr.ReadLine()) && -1 != GetIndexOf(line, "bldgA", ','); )
        {
            Console.WriteLine("You are in bldgA and your name is {0} and your duty is {1}",
                line.Split(',')[GetIndexOf(line, "bldgA", ',') + 1].Trim(),
                line.Split(',')[GetIndexOf(line, "bldgA", ',') + 2].Trim());
        }
    }
}
Hao Wooi Lim