Powershellのコードは簡単に字句解析ができることを知ったので、その方法のメモ。
使うもの
PSParser.Tokenize Method (System.Management.Automation) | Microsoft Docs
上記のメソッドにコードを渡せば、解析結果を返してくれます。
使用例
PowerShell自身で実行してみる場合のコードです。
# 字句解析したいスクリプト文字列
[string]$code = {Get-ChildItem -LiteralPath $PSHOME -Filter *.exe}.ToString()
<# $code =>
Get-ChildItem -LiteralPath $PSHOME -Filter *.exe
#>
# 解析エラーを入れる変数。中身は`Tokenize`内で設定されるため$nullでOK
[Collections.ObjectModel.Collection[Management.Automation.PSParseError]]$parseErrors = $null
# トークン化
[Management.Automation.PSToken[]]$tokens =
[Management.Automation.PSParser]::Tokenize($code, [ref]$parseErrors)
# 表示用に整形
$tokens | Format-Table -AutoSize
結果
Content | Type | Start | Length | StartLine | StartColumn | EndLine | EndColumn |
---|---|---|---|---|---|---|---|
Get-ChildItem | Command | 0 | 13 | 1 | 1 | 1 | 14 |
-LiteralPath | CommandParameter | 14 | 12 | 1 | 15 | 1 | 27 |
PSHOME | Variable | 27 | 7 | 1 | 28 | 1 | 35 |
-Filter | CommandParameter | 35 | 7 | 1 | 36 | 1 | 43 |
*.exe | CommandArgument | 43 | 5 | 1 | 44 | 1 | 49 |
各トークン毎に、中身・種類・文字列中どの位置なのか、が取得できているのが分かります。
補足
基本は書いてある通りですが、いくつか気になった点があったのでその補足です。
構文エラーも無視して解析される
[Management.Automation.PSParser]::Tokenize
は構文エラーがあった場合も、最後まで解析が行われ結果が返ります。
構文エラーを確認したい場合は、第2引数(上記のコードだと$parseErrors
)の個数や中身をチェックします。
ただし、上記のコードではスクリプトブロックをToString()
しているため、構文エラーがある場合はスクリプトブロック生成段階でエラーが起きます。
空白はトークンではない
当たり前といえば当たり前の話ではありますが、スペースなどはトークンとして認識されません。
ただし、改行に関してはNewLine
というTypeで表現されます。
変数の$
はContent
に含まれない
PowerShellの変数は$
から始まりますが、先頭の$
は結果のContent
に含まれません。
$
も含めた範囲を取得したい場合は、以下のように元の文字列からSubStringで切り出す必要があります。
$tokens |
ForEach-Object -Process {
$code.Substring($_.Start, $_.Length)
}