C# 使用C标记自定义文本文件格式文件#

C# 使用C标记自定义文本文件格式文件#,c#,parsing,tokenize,C#,Parsing,Tokenize,我想解析一种基于文本的文件格式,它的语法有点古怪。以下是一些有效的示例行: <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 是否有一个好的库/教程可以为我指明实现这一目标的正确方向 更

我想解析一种基于文本的文件格式,它的语法有点古怪。以下是一些有效的示例行:

<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
是否有一个好的库/教程可以为我指明实现这一目标的正确方向


更新:我试过这样做,但是我需要解析的语法的怪癖(特别是sample=后面的数据可以有一个空格的事实)让他们建议我最好基于String.Split编写自己的代码。参见讨论。

对于这种类型的东西,我会得到轻量级但健壮的。如果你再给我看一些示例输入,我可能会想出一个语法起点


我以前使用过lex和yacc,所以我有一些解析经验马克·希思17分钟前

你很幸运:我在Fedora的soundfont utils包中找到了一个用于
sfz
的lex语法。该软件包包含。您可以在此处获取(源)包:

()

根据快速调查,最新版本的语法是从2004年11月开始的,但相当详细(sfz2pat.l中的58k)。以下是一个品尝的样品:

%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...]
%选项noyywrap
%期权看跌期权
%选项outfile=“sfz2pat.c”
nm([^\n]+“.wav”\[^\t\n\r]+\“[^\”\n]+\”)
ipn[A-Ga-g][#b]?([0-9]|“-1”)
%s K
%%
"//".*  ;
""    {
int i;
离开_区域();
离开_组();
如果(!输入组()){
SFZERR
“无法启动组\n”);
返回1;
}
am_in_group_scope=TRUE;
对于(i=FIRST_SFZ_PARM;i
假设该语言相当规则,我建议使用编写一个快速解析器。对于有解析经验的人来说,它有一个非常简单的学习曲线,它输出C#(以及其他内容)。

我使用和生成解析器。它们工作得很好,特别是如果你有一些lex/yacc知识的话

在我看来,这两个是.NET最好的解析器生成器


一个优点是:可以看到,创建者对bug报告和建议的响应很快。

谢谢,我会研究一下。文件格式规范是这个文件格式sfz吗?谷歌很难,如果是,请提及它,格式是,但我通常对解决这类问题的最佳方法感兴趣,而不管sfz的具体情况如何我会试试这个。我以前用过lex和yacc,所以我有一些解析经验。
%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...]