2011-04-23 51 views
0

我正在研究一个HTML5/JavaScript游戏引擎,并且我已经开始遇到过去从未出现过的情景,弄清楚我可以如何解决这个问题。通过不包含在括号内的冒号来分割字符串()

简而言之,我想通过一个字符将字符串拆分成一个数组 - 只要该字符不在括号内。

基本上,在物品/瓷砖之类的XML文件中,我存储了“触发器”,它们是为代码执行的操作提供规则的语句。单个触发器的不同参数用冒号(:)分开,并且可以为一个项目放置多个触发器,每个触发器都用逗号分隔。这里有一个例子:

<response trigger="npc:self:dialog:1:3">No, thank you.</response> 

(这基本上是说:如果选择了这种反应,让谁问最初的问题循环到特定转换的特定邮件的NPC)

一起运动:我已经开始需要能够将回调触发器封装在具有某些触发器的参数括号内。这里有一个例子:

<response trigger="shop:open:1:(npc:self:dialog:1:4)">Yes, please.</response> 

(这基本上是说:打开一个特定的商店,当商店被关闭,跳转到一个特定的会话/消息讲NPC)

的想法是,当商店关闭时,我可以调用该触发器的第四个参数(这本身就是一个触发器)。我相信你已经猜到了,这里的问题是,如果我根据“:”分割初始触发字符串,那么它会将回调触发器分解为主触发器的其他(杂乱)参数。我不想那样。另外,我也不想做任何事情,例如将其他角色分割为次级触发器(稍后出于生成原因,因为我想有些时候我会想在更深层次上嵌套大量触发器,而且我不想使用不同的字符我知道的解决方法,但我想学习正确的方式来分割一个字符,不包含在其他特定字符中

因为我用括号封装了回调参数,必须有一个干净的正则表达式我可以使用所有冒号内部没有括号分裂的主要触发字符串。

可悲的是,我一直没能拿出合适的表情来完成这件事。

任何想法?

我非常感谢你们的任何帮助。 :)

+0

确定是否可以使用正则表达式分析的关键问题:括号可以嵌套吗? – cobbal 2011-04-23 18:12:19

+0

@cobbal:我会说是,引用“我想有些时候我会想在更深层次上嵌套大量的触发器”。 – 2011-04-23 18:31:34

+0

@ChristianSemrau啊,我似乎错过了那一点。 – cobbal 2011-04-23 18:38:33

回答

0

有一个很好的理由,为什么你无法找到一个正则表达式你的问题:

您所描述的语言是不正规,即不能用正则表达式进行解析。

基本上,您必须解析括号结构以确定所有括号外的冒号。这是不可能的正则表达式。

嵌套括号的语言是上下文无关的[1],因此它直接编写递归解析器。

[1] http://en.wikipedia.org/wiki/Context-free_language

此外:你并不需要一个递归语法分析器,用于括号嵌套层次简单的计数器就足够了:

// Pseudo code 
int depth = 0; 
List<int> breakIndices; 
for int index = 0 .. input.length-1: 
    switch(input[index]) 
    ':': if (depth==0) breakIndices.add(index); break; 
    '(': depth++; break; 
    ')': depth--; break; 
    default: break; 
// Now, all indices of the colons you need are in the breakIndices list. 
+0

感谢您的洞察力和示例方法。我承认,也许我是一厢情愿的想法,因为单线可以把它拉开,所以我会玩弄你的例子(和另一个在这里提供),并把它们合在一起。 - 再次,我感谢你解释为什么这甚至不是一个正则表达式场景。 – Lev 2011-04-23 18:46:44

+0

确实。但我知道没有证据表明扩展的正则表达式引擎可以解析嵌套括号的语言。 – 2011-04-23 19:56:35

1

我怀疑你不能,至少如果有任何嵌套括号的机会,因为识别正确的括号嵌套是不规则的。

在任何情况下,不要构建一些巴洛克式的正则表达式,而要考虑一个非常简单的解析器:扫描到下一个出现的“:”或“(”,并对下一个标记进行处理,重复。容易做到用递归下降,并会看起来像

parse(string) 
    if string is empty: return 
    scan to delimiter, put delimiter index into d, token string into t 
    put t into a table for processing later 
    case on d: 
     string[d] == ":": parseColonToken(string[d+1:]) 
     string[d] == "(": parseParentString(strin[d+1:]) 
    end 
end 

(显然,这是伪代码。以string[n:]为“从指数ñ到年底的string子。)

可能,想想看,你只需从01开始但我不确定这是否符合您的预期语法。

+0

我现在感觉到,当我花了很长时间写出失败的表达式时,你不能这样做,然后你的前两个人似乎很确定这不是一个正则表达式场景。我很欣赏示例代码 - 我会玩弄一些类似的解析器。我认为我希望有一点不切实际的想法。 > _ < – Lev 2011-04-23 18:48:54

+0

假设父亲可以嵌套,那么这是一个定理,你不能。老实说,这个递归下降的事情非常简单,我一直在考虑下午的其他用途。 – 2011-04-24 03:25:06

0

我认为最简单的方法是将字符串分解为“函数”部分和“参数”部分,然后分别处理这两部分。如果你想保持参数的一部分括号,然后:

var parts1 = "shop:open:1:(npc:self:dialog:1:4)".split(/:(?=\()/); 
// parts1 now looks like ["shop:open:1", "(npc:self:dialog:1:4)"] 
var parts2 = "shop:open:1".split(/:(?=\()/); 
// parts2 now looks like ["shop:open:1"] 

然后:

var cmd = null; 
var arg = null; 
if(parts.length > 0) { 
    cmd = parts[0].split(':'); 
    arg = (parts[1] || '').replace(/[()]/g, '').split(':'); 
} 

您可能能够更多,要塞进一个单独的正则表达式(也可能是这一切取决于您的目标正则表达式引擎支持的非常规功能),但没有太多的重点和清晰度是您的代码比“短”更好的目标。看到上述内容的任何人都应该能够弄清楚自己在做什么,如果他们手头有decent JavaScript regex reference

如果你最终处理更复杂的引用和转义等表达式,那么你可以尝试修改a CSV parser来做你所需要的。

相关问题