簡體   English   中英

使用PEG.js簡單解析問題

[英]Simple parsing questions using PEG.js

我試圖通過在PEG.js操場上輸入簡單的語法來繞過PEG。

例1:

  • 輸入: "abcdef1234567ghijklmn8901opqrs"
  • 期望的輸出: ["abcdef", "1234567", "ghijklmn", "8901", "opqrs"]

  • 實際輸出: ["abcdef", ["1234567", ["ghijklmn", ["8901", ["opqrs", ""]]]]]

這個例子非常有效,但是我可以讓PEG.js不將生成的數組嵌套到百萬級別嗎? 我假設訣竅是在某處使用concat()而不是join() ,但我找不到這個地方。

start
  = Text

Text
  = Numbers Text
  / Characters Text
  / EOF

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Characters
  = text: [a-z]+ {return text.join("")}

EOF
  = !.

例2:

與示例1相同的問題和代碼,但將字符規則更改為以下內容,我預期會產生相同的結果。

Characters
  = text: (!Numbers .)+ {return text.join("")}

結果輸出是:

[",a,b,c,d,e,f", ["1234567", [",g,h,i,j,k,l,m,n", ["8901", [",o,p,q,r,s", ""]]]]]

為什么我得到所有這些空的比賽?

例3:

最后一個問題。 這根本不起作用。 我怎樣才能使它工作? 對於獎勵積分,任何關於效率的指針? 例如,如果可能,我應該避免遞歸嗎?

我也很欣賞一個很好的PEG教程的鏈接。 我已閱讀( http://www.codeproject.com/KB/recipes/grammar_support_1.aspx ),但正如您所見,我需要更多幫助......

  • 輸入: 'abcdefghijklmnop"qrstuvwxyz"abcdefg'
  • 期望的輸出: ["abcdefghijklmnop", "qrstuvwxyz", "abcdefg"]
  • 實際輸出: "abcdefghijklmnop\\"qrstuvwxyz\\"abcdefg"
start
  = Words

Words
  = Quote
  / Text
  / EOF

Quote
  = quote: ('"' .* '"') Words {return quote.join("")}

Text
  = text: (!Quote . Words) {return text.join("")}

EOF
  = !.

我收到了PEG.js Google Group的回復,幫助我走上正軌。 我正在發布所有三個問題的答案,希望它們可以作為像我這樣的其他PEG初學者的基礎教程。 請注意,不需要遞歸。

例1:

一旦你理解了基本的PEG習語,這很簡單。

start
  = Text+

Text
  = Numbers
  / Characters

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Characters
  = text: [a-z]+ {return text.join("")}

例2:

這里的問題是Peek表達式(&expr和!expr)的PEG.js解析器生成器中的一種特殊設計選擇。 兩者都在不消耗任何字符的情況下向前查看輸入流,因此我錯誤地認為它們沒有返回任何內容。 但是,它們都返回一個空字符串。 我希望PEG.js的作者改變這種行為,因為(據我所知)這只是污染輸出流的不必要的瑕疵。 如果我錯了,請糾正我!

無論如何,這是一個解決方法:

start
  = Text+

Text
  = Numbers
  / Words

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Words
  = text: Letter+ {return text.join("")}

Letter
  = !Numbers text: . {return text}

例3:

問題是像('"' .* '"')這樣的表達式永遠不會成功。 PEG總是貪婪的,所以.*將消耗其余的輸入流,永遠不會看到第二個引用。 這是一個解決方案(順便說一下,需要與示例2中相同的Peek解決方法)。

start
  = Words+

Words
  = QuotedString
  / Text

QuotedString
  = '"' quote: NotQuote* '"' {return quote.join("")}

NotQuote
  = !'"' char: . {return char}

Text
  = text: NotQuote+ {return text.join("")}

對於當前版本的pegjs ,您可以嘗試:

例一

輸入: "abcdef1234567ghijklmn8901opqrs"

期望的輸出: ["abcdef", "1234567", "ghijklmn", "8901", "opqrs"]

{
  /**
   * Deeply flatten an array.
   * @param  {Array} arr - array to flatten
   * @return {Array} - flattened array
   */
  const flatten = (arr) =>  Array.isArray(arr) ? arr.reduce((flat, elt) => flat.concat(Array.isArray(elt) ? flatten(elt) : elt), []) : arr
}

start = result:string {
  console.log(JSON.stringify(result))
  return result
}

string = head:chars tail:( digits chars? )* {
  return flatten([head,tail])
}

chars = [a-z]+ {
  return text()
}

digits = $[0-9]+ {
  return text()
}

例2

應該很容易從上面的答案中推斷出來。

例3

輸入: 'abcdefghijklmnop"qrstuvwxyz"abcdefg'

期望的輸出: ["abcdefghijklmnop", "qrstuvwxyz", "abcdefg"]

{
  /**
   * Deeply flatten an array.
   * @param  {Array} arr - array to flatten
   * @return {Array} - flattened array
   */
  const flatten = (arr) =>  Array.isArray(arr) ? arr.reduce((flat, elt) => flat.concat(Array.isArray(elt) ? flatten(elt) : elt), []) : arr
}

start = result:string {
  console.log(JSON.stringify(result))
  return result
}

string = head:chars tail:quote_chars* {
  return flatten([head,tail])
}

quote_chars = DQUOTE chars:chars {
  return chars
}

chars = [a-z]+ {
  return text()
}

DQUOTE = '"'

例1

start
  = alnums

alnums
  = alnums:(alphas / numbers) {
    return alnums;
  }

alphas
  = alphas:$(alpha+)

numbers
  = numbers:$(number+)

number
  = [0-9]

alpha
  = [a-zA-Z]

例2

忽視

例3

> 'abcdefghijklmnop"qrstuvwxyz"abcdefg'.split('"')
[ 'abcdefghijklmnop',
  'qrstuvwxyz',
  'abcdefg' ]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM