2011-04-23 132 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來做你所需要的。

相關問題