Пытаюсь написать приятный парсер - PullRequest
3 голосов
/ 01 февраля 2010

Я пишу простой парсер, который возьмет строку в формате 20100101,1,2,foo и создаст экземпляр следующего класса:

public class Foo
{
    public DateTime TheDate { get; set; }
    public int TheFirstInt { get; set; }
    public int TheSecondInt { get; set; }
    public string TheString { get; set; }
}

Я хотел бы иметь возможность объявить мои синтаксические анализаторы для каждого свойства как массив (например) Func<>s в попытке сделать код более читабельным (с точки зрения корреляции элементов в строке с код разбора, который используется).

// Production code would contain parsers with error checking etc.
Func<string, object>[] parsers = new Func<string, object>[]
{
    s => DateTime.ParseExact(s, "yyyyMMdd", CultureInfo.InvariantCulture),
    s => int.Parse(s),
    s => int.Parse(s),
    s => s
};

Затем я хотел бы иметь возможность перебирать парсеры, свойства FooClass и значения в fooItems в одном цикле:

Foo fooInstance = new Foo();
string[] fooItems = fooString.Split(',');

for (int i = 0; i < parsers.Length; i++)
{
    fooInstance.Properties[i] = parsers[i](fooItems[i]);
    // range-checking and error handling excluded from this example
}

Однако это, конечно, не сработает, потому что:

  • Это не касается того, как вы можете перебирать свойства fooInstance
  • Это не относится к приведению значений, проанализированных

Есть какие-нибудь мысли о том, как написать "приятный" парсер, подобный этому?

Ответы [ 3 ]

2 голосов
/ 01 февраля 2010

Я бы попробовал использовать Action s вместо Func s и установить свойства напрямую:

Action<string, FooClass>[] actions = new Action<string, FooClass>[] {
    (s, c) => c.TheDate = DateTime.ParseExact(s, "yyyyMMdd", CultureInfo.InvariantCulture),
    (s, c) => c.TheFirstInt = Int32.Parse(s)
    // ...
}

for (int i = 0; i < fooItems.Length; ++i)
    actions[i](fooItems[i], fooInstance);
2 голосов
/ 01 февраля 2010

Я знаю, что это не ответ на ваш вопрос напрямую, но если вы обнаружите, что ваш "язык" становится намного сложнее, я рекомендую использовать Irony для его анализа: http://www.codeplex.com/irony

Если ваш язык собираетсяоставайтесь в плоском формате (например, CSV), тогда стоит посмотреть http://www.filehelpers.com/

. В вашем примере вам просто нужно аннотировать ваш класс:

[DelimitedRecord(",")]
public class Foo
{
    [FieldConverter(ConverterKind.Date, "yyyyMMdd")]
    public DateTime TheDate { get; set; }
    public int TheFirstInt { get; set; }
    public int TheSecondInt { get; set; }
    public string TheString { get; set; }
}

, а затем проанализировать его.с:

FileHelperEngine engine = new FileHelperEngine(typeof(Foo));
Foo[] fs = engine.ReadFile("FileIn.txt") as Foo[];
0 голосов
/ 01 февраля 2010

Вам нужно использовать отражение: например:

fooInstance.GetType().GetProperty("SomeProp").SetValue(fooInstance, "SomeProp", val);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...