Как мне лучше всего разобрать этот текстовый файл с разделителями-запятыми? - PullRequest
1 голос
/ 16 января 2009

Я пытаюсь найти лучший способ разбора этого текстового файла с разделителями-запятыми. Вот выдержка:

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

То, что я пытаюсь сделать, это прочитать «bldgA», а затем мне нужен человек (2-й столбец), например, «fred». Но я не хочу анализировать файл в поисках «fred», потому что fred может не появиться в следующий раз, тогда как bldgA всегда будет. Я хочу прочитать текстовый файл, увидеть, что я нахожусь на bldgA, и прочитать следующий элемент в моем списке, который является Фред. После этого я хочу проверить, если это Фред, Салли и т. Д. И распечатать третий столбец. Я знаю, что это может быть проще с базой данных, но для небольшого текстового файла это немного излишне, так что я могу назвать столбцы. Прежде чем прибегнуть к Access или к чему-то маленькому, я подумал, что попробую переполнение стека. Вот что у меня есть:

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();

Мой окончательный результат будет

"Вы находитесь в здании, и вас зовут Фред, и ваш долг - обед"

Ответы [ 8 ]

3 голосов
/ 16 января 2009

Если вы знаете, что файл ВСЕГДА будет правильно отформатирован, вы можете сделать что-то вроде (используя ваш код, предполагая, что язык 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();
2 голосов
/ 16 января 2009

Используйте библиотеку FileHelpers . Он позволяет вам создавать классы для хранения ваших данных и обеспечивает простой способ анализа хранилища данных (включая csv) для заполнения этих классов.

Но, как вы предположили, это похоже на работу с базой данных. Я бы рассмотрел SQLite .

1 голос
/ 16 января 2009

Объект дБ лучше для вашего решения. Вы можете использовать db4o , очень хороший открытый код.

Но если вы настаиваете на использовании файла с разделителями-запятыми, взгляните на этот CsvReader , вы можете использовать его для чтения файла.

1 голос
/ 16 января 2009

Вместо использования цикла foreach, почему бы вам не сделать что-то вроде этого:

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
0 голосов
/ 30 января 2009

Простите за программирование, но я думаю, что это может решить вашу проблему.

Единственное допущение, которое я сделал, заключается в том, что где-то в building.txt есть столбец с именем "bldgA", и справа от него всегда есть еще 2 столбца, и это те данные, которые вам нужны.

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());
        }
    }
}
0 голосов
/ 16 января 2009

В псевдокоде:

#!/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()) 
0 голосов
/ 16 января 2009

Я думаю, что ваша выдержка предназначена так:

bldgA, Фреда, обед
bldgA, вылазка, ужин
дом, боб, автостоянка
bldgB, откровенный, на крыше

Шаги для получения желаемого результата:

  • читать одну строку
  • разделить строку по запятым
  • отформатируйте желаемый результат с частями, возвращенными функцией разделения

Функция split часто является частью библиотеки регулярных выражений.

В Common Lisp это можно написать так:

(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)))))

В Perl вы можете использовать что-то вроде этого:

#!/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."; };

Обратите внимание, что версия Perl предназначена для использования в качестве отдельного сценария, а версия CL показывает функцию, которая будет использоваться из среды выполнения. Здесь также нет проверки ввода.

0 голосов
/ 16 января 2009

Используйте конечный автомат, в основном. Имейте переменную под названием «здание» и сохраняйте там название здания, когда вы его встретите. Затем рассмотрите имена людей, которые работают в этом здании.

Ваше объяснение не очень понятно, а ваш пример странный. Если вы можете перефразировать, что я, скорее всего, мог бы дать лучший ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...