【问题标题】:Regex for splitting txt db file用于拆分 txt db 文件的正则表达式
【发布时间】:2013-04-12 16:27:52
【问题描述】:

我正在编写一个 txt 数据库文件到 sql 转换器,我需要拆分行中的项目。问题是在这些项目中可能有可以包含多个逗号的脚本(它们是 db 结构中的分隔符)。好消息是,脚本嵌套在 {}-s 中,因此它使工作类似于解析 csv 文件。唯一的问题是脚本本身可以容纳更多嵌套在 {}-s 中的脚本,这会阻止我的公式工作..

txt 数据库的结构:

501,Red_Potion,Red Potion,0,50,,70,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(45,65),0; },{},{}
502,Orange_Potion,Orange Potion,0,200,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(105,145),0; },{},{}
503,Yellow_Potion,Yellow Potion,0,550,,130,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(175,235),0; },{},{}
504,White_Potion,White Potion,0,1200,,150,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(325,405),0; },{},{}

我用来匹配分隔符以进行拆分的正则表达式:

,(?![^{}]*\})

这可以正常工作,直到它对抗更复杂的嵌套脚本项,例如:

1492,Velum_Glaive,Vellum Glaive,4,20,,4500,250,,3,0,0x00004082,7,2,34,4,95,1,5,{ bonus2 bAddRace,RC_DemiHuman,80; if(getrefine()>=6) { bonus2 bSkillAtk,"LK_SPIRALPIERCE",100; bonus2 bSkillAtk,"KN_SPEARBOOMERANG",50; } if(getrefine()>=9) { autobonus2 "{ bonus bShortWeaponDamageReturn,20; bonus bMagicDamageReturn,20; }",100,2000,BF_WEAPON|BF_MAGIC,"{ specialeffect2 EF_REFLECTSHIELD; }"; } },{},{}

那么如何让它只匹配 db 结构分隔符而将脚本中的逗号排除在外?

提前致谢! :)

【问题讨论】:

  • 嵌套结构是正则表达式方法通常崩溃的地方。根据您的正则表达式风格,您可能能够使用递归构造 (PCRE) 或平衡组 (.NET),但解决方案通常会变得丑陋。您可能应该手动逐个字符地遍历字符串,并计算左大括号和右大括号的嵌套级别。
  • 您也许可以使用快捷方式,但要受到非常特定的限制。如果您的嵌套脚本中没有,{},,那么您可以非常轻松地使用环视。否则,正如@m.buettner 指出的那样,这不是正则表达式的真正工作。
  • 另外,不要忘记脚本字符串中的大括号可能不匹配。因此,实际上您甚至还必须计算脚本中的字符串和 cmets。

标签: regex split comma separator


【解决方案1】:

这不是正则表达式的工作。正如我在评论中指出的那样,嵌套结构通常超出了正则表达式的能力。 PCRE 具有递归构造 (?R),而 .NET 具有平衡组,但解决方案通常变得非常不可读和不可维护。

此外,您不仅需要考虑{},还需要考虑脚本中的字符串和 cmets。你会好很多,手动解析东西。这是一个快速而肮脏的例子,它是如何使用 PHP 完成的(忽略字符串和 cmets!):

$level = 0;
$values = array();
$start = 0;
for($i = 0; $i < strlen($str); $i++)
{
    switch($str[$i])
    {
    case ",":
        if(!$level) {
            $values[] = substr($str, $start, $i-$start);
            $start = $i+1;
        }
        break;
    case "{":
        $level++;
        break;
    case "}":
        $level--;
        if($level < 0) trigger_error("unexpected }");
        break;
    }
}
if($level > 0) trigger_error("missing }");
$values[] = substr($str, $start);

您已经可以看到,您基本上得到了一个更简单的脚本解析器。

【讨论】:

  • 实际上我最终用特殊字符替换了脚本边框并为此应用了正则表达式。不是最好的,但它对代码的更改最少:)
  • @Angezerus 是的,听起来像是一个很好的解决方法......只是要小心包含这些字符的字符串;)
猜你喜欢
  • 1970-01-01
  • 2017-06-24
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多