Токенизация файла пользовательского формата текстового файла с использованием C # - PullRequest
4 голосов
/ 08 мая 2011

Я хочу проанализировать текстовый формат файла, имеющий немного необычный синтаксис.Вот несколько примеров правильных строк:

<region>sample=piano C3.wav key=48 ampeg_release=0.7 // a comment here
<region>key = 49 sample = piano Db3.wav
<region>
group=1
key = 48
    sample = piano D3.ogg

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

new Region(), new Sample("piano C3.wav"), new Key("48"), new AmpegRelease("0.7"), new Region()

Есть ли хорошийбиблиотека / учебник, который укажет мне правильное направление для элегантного способа реализации этого?

Обновление: Я пробовал это с Ирония , но причудысинтаксис, который мне нужно проанализировать (в частности, тот факт, что данные, следующие за образцом, могут содержать пробел), заставил их предположить, что мне лучше написать собственный код на основе String.Split.Смотрите обсуждение здесь .

Ответы [ 3 ]

2 голосов
/ 08 мая 2011

Для такого типа вещей я бы получил легкий, но надежный CoCo / R . Если вы покажете мне еще несколько примеров ввода, я мог бы предложить начальную точку грамматики.


Я раньше использовал lex и yacc, поэтому у меня есть некоторый опыт разбора. - Марк Хит 17 минут назад

Ну, вам повезло: я нашел лексическую грамматику для sfz в пакете Fedora soundfont-utils. Этот пакет содержит утилиту sfz2pat . Вы можете получить (исходный) пакет здесь:

http://rpmfind.net//linux/RPM/fedora/14/i386/soundfont-utils-0.4-10.fc12.i686.html ( src.rpm )

Согласно быстрому исследованию последняя версия грамматики относится к ноябрю 2004 года, но довольно сложна (58k в sfz2pat.l) Вот образец, чтобы получить вкус:

%option noyywrap
%option nounput
%option outfile = "sfz2pat.c"

nm  ([^\n]+".wav"|[^ \t\n\r]+|\"[^\"\n]+\")
ipn [A-Ga-g][#b]?([0-9]|"-1")

%s  K

%%

"//".*  ;

<K>"<group>"    {
    int i;
    leave_region();
    leave_group();
    if (!enter_group()) {
        SFZERR
        "Can't start group\n");
        return 1;
    }
    am_in_group_scope = TRUE;
    for (i = FIRST_SFZ_PARM; i < MAX_SFZ_PARM; i++) group_parm[i] = default_parm[i];
    for (i = 0; i < MAX_FLOAT_PARM; i++) group_flt_parm[i] = default_flt_parm[i];
    group_parm[REGION_IN_GROUP] = current_group;
    BEGIN(0);
}
<K>"<region>"   {
    int i;
    if (!am_in_group) {
        SFZERR
        "Can't start region outside group.\n");
        return 1;
    }
    leave_region();
    if (!enter_region()) {
        SFZERR
        "Can't start region\n");
        return 1;
    }
    am_in_group_scope = FALSE;
    for (i = 0; i < MAX_SFZ_PARM; i++) region_parm[i] = group_parm[i];
    for (i = 0; i < MAX_FLOAT_PARM; i++) region_flt_parm[i] = group_flt_parm[i];
    BEGIN(0);
}
<K>"sample="{nm} {
    int i = 7, j;
    unsigned namelen;
    if (yytext[i] == '"') {
        i++;
        for (j = i; j < yyleng && yytext[j] != '"'; j++) ;
    }
    else j = yyleng;
    namelen = (unsigned)(j - i + 1);
    sfzname = strncpy( (char *)malloc(namelen), yytext+i, (unsigned)(j-i) );
    sfzname[j-i] = '\0';
    for (i = 0; i < (int)namelen; i++) if (sfzname[i] == '\\') sfzname[i] = '/';
    SFZDBG
    "Sample name is \"%s\"", sfzname);
    SFZNL
    if (read_sample(sfzname)) {
#ifndef LOADER
        fprintf(stderr, "\n");
#endif
        return 0;
    }
    BEGIN(0);
}
[...snip...]
1 голос
/ 08 мая 2011

Я использовал Gardens Point LEX и Gardens Point Parser Generator для генерации парсеров. Они хорошо работают, особенно если у вас есть знания lex / yacc.

IMO, эти два делают лучший генератор парсера для .NET.

Один бонусный момент: создатели быстро реагируют на сообщения об ошибках и предложения, как можно увидеть здесь .

1 голос
/ 08 мая 2011

Предполагая, что язык довольно обычный, я бы порекомендовал написать быстрый парсер, используя ANTLR .Он имеет довольно простую кривую обучения для кого-то с опытом разбора, и он выводит C # (среди прочего).

...