我正在开发一个HTML5 / JavaScript游戏引擎,我已经开始遇到一个过去从未有过的场景,也无法弄清楚如何解决这个问题。
简单地说,我想用字符将字符串拆分成数组 - 只要该字符不在括号内。
基本上,在诸如items / tiles之类的XML文件中,我存储了“triggers”,这些语句为代码将执行的操作提供规则。单个触发器的不同参数用冒号(:)分开,并且一个项目可以有多个触发器,每个触发器用逗号分隔。这是一个例子:
<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的特定对话/消息)
这个想法是当商店关闭时,我可以调用该触发器的第4个参数(这是一个触发器本身)。我相信你已经猜到了,这里的问题是如果我基于“:”分割初始触发字符串,那么它会将回调触发器作为主触发器的其他(杂乱)参数分解。我不希望这样。也不是,我想做任何事情,比如用另一个角色分割次要触发器(由于后来的生成原因,并且因为我想有时候我会想要在更深层次上嵌套大量触发器而且我不想使用不同的角色。我知道解决方法,但我想学习用一个不包含在其他特定角色中的角色来分割的正确方法。
由于我用括号封装回调参数,我认为必须有一个干净的正则表达式,我可以用它来分割所有冒号NOT INSIDE括号的主触发器字符串。
可悲的是,我无法提出正确的表达方式来完成这项任务。
有什么想法吗?
我非常感谢你们任何人的帮助。 :)
答案 0 :(得分: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
的子字符串从索引 n 到结尾。”
可能,考虑一下,你只需要从parseColonToken
开始,但我不确定这是否符合你预期的语法。
答案 1 :(得分: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.
答案 2 :(得分: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以执行您需要的操作。