regex - 使用正则表达式在 Powershell 中解析 INI 文件
问题描述
我正在尝试改进原始解决方案(PowerShell 中的 INI 文件解析),因此我可以解析一个带有条目的 INI 文件,如下例所示。
[proxy]
; IP address and port number
server = 192.168.0.253
port = 8080
logfile=session.log ; log session
[user]
; default username and settings
name=J. Doe ;name
address="377 Sunrise Way;Santa Monica;CA" ; address
[program files]
root="C:\Program Files\Windows " ; path name
path="C:\Program Files\Windows;%windir" ; path name
;
[program]
root=C:\Program Files\Windows ; path name
path=C:\Program Files\Windows;%windir ; path name
我正在使用以下 powershell 代码填充包含每个部分的名称/值对的嵌套哈希表(如果这是正确的描述)。
我在处理以注释结尾的第一部分或第二部分中包含空格的值时没有问题,但是当我尝试混合引用的字符串和注释时出现问题。
鉴于字符串以双引号开头和结尾,我认为应该可以获得我想要的结果,但我显然在某处遗漏了一些东西(我对此有点陌生)。
function Parse-INI-File() {
Param ([parameter()][string]$_file = '')
# Don't prompt to continue if '-Debug' is specified.
If ($DebugPreference -eq "Inquire") {$DebugPreference = "Continue"}
$_settings=@{}
switch -Regex -file $_file {
'(?:^ ?\[\s*(?<section>[^\s]+[^#;\r\n\[\]]+)\s*\])' {
$_section = $Matches.section.trim()
$_settings[$_section] = @{}
}
'(?:^\s*?(?<name>[^\[\]\r\n=#;]+))(?: ?=\s*"?(?<value>[^;#\\\r\n]*(?:\\.[^"#\\\r\n]*)*))' {
$_name, $_value = $Matches.name.trim(), $matches.value.trim()
$_settings[$_section][$_name] = $_value
Write-Debug "/$_section/ /$_name//$_value/" # Debug
}
}
$_settings
}
$_file='./ini-example.ini'
$_output=Parse-INI-File -Debug ($_file)
我想要的是解析示例 ini 文件以生成以下名称/值对:
DEBUG: /proxy/ /server//192.168.0.253/
DEBUG: /proxy/ /port//8080/
DEBUG: /proxy/ /logfile//session.log/
DEBUG: /user/ /name//J. Doe/
DEBUG: /user/ /address//377 Sunrise Way;Santa Monica;CA/
DEBUG: /program files/ /root//C:\Program Files\Windows/
DEBUG: /program files/ /path//C:\Program Files\Windows;%windir/
DEBUG: /program/ /root//C:\Program Files\Windows/
DEBUG: /program/ /path//C:\Program Files\Windows/
我不介意引用的字符串是否包含原始引号。
谢谢你。
2019 年 9 月 10 日更新 - 我尝试了 psini 模块中的 Get-IniContent 函数,但它不会忽略行尾的注释。
PS C:\> $_output = Get-IniContent (".\ini-example.ini")
PS C:\> $_output["program files"]
Name Value
---- -----
root "C:\Program Files\Windows "' ; path name
path "C:\Program Files\Windows;;%windir" ; path name
Comment1 ;
PS C:\>
解决方案
认为我已经解决了它,可能有更好的解决方案,但我通过对引用字符串使用单独的正则表达式解决了这个问题 - 这使逻辑有点复杂,但似乎可靠地解决了问题。
function Parse-INI-File() {
Param ([parameter()][string]$_file = '')
# Don't prompt to continue if '-Debug' is specified.
If ($DebugPreference -eq "Inquire") {$DebugPreference = "Continue"}
$_settings=@{}
switch -Regex -file $_file {
'(?:^ ?\[\s*(?<section>[^\s]+[^\r\n\[\]]+)\s*\])' {
$_section = $Matches.section.trim()
$_settings[$_section] = @{}
#Write-Debug "1/$_section/" # Debug
}
'(?:^\s*?(?<name>[^\[\]\r\n]+))(?: ?=\s*(?<value>[^";#\\\r\n]*(?:\\.[^";#\\\r\n]*)*))' {
If ($matches.value -ne '' ) {
$_name, $_value = $Matches.name.trim(), $matches.value.trim()
$_settings[$_section][$_name] = $_value
Write-Debug "2/$_section//$_name//$_value/" # Debug
}
}
'(?:^\s*?(?<name>[^\[\]\r\n]+))(?: ?=\s*(?<value>\"+[^\"\r\n]*\")*)' {
#If ($matches.value -ne $null ) {
If (-not [string]::IsNullOrEmpty($matches.value)) {
$_name, $_value = $Matches.name.trim(), $matches.value.trim()
$_settings[$_section][$_name] = $_value
Write-Debug "3/$_section//$_name//$_value/" # Debug
}
}
}
$_settings
}
这似乎产生了我期望的结果
PS C:\> $_output = Parse-INI-File -Debug (".\ini-example.ini")
DEBUG: 2/proxy//server//192.168.0.253/
DEBUG: 2/proxy//port//8080/
DEBUG: 2/proxy//logfile//session.log/
DEBUG: 2/user//name//J. Doe/
DEBUG: 3/user//address//"377 Sunrise Way;Santa Monica;CA"/
DEBUG: 3/program files//root//"C:\Program Files\Windows "/
DEBUG: 3/program files//path//"C:\Program Files\Windows;%windir"/
DEBUG: 2/program//root//C:\Program Files\Windows/
DEBUG: 2/program//path//C:\Program Files\Windows/
PS C:\> $_output["user"]
Name Value
---- -----
name J. Doe
address "377 Sunrise Way;Santa Monica;CA"
PS C:\>
请注意,如果一个部分中有多个具有相同名称的值,则仅返回最后一个值(尝试解析 system.ini 以了解我的意思)
推荐阅读
- azure-devops - 从 repo 构建特定的解决方案文件
- swift - 如何修复显示屏上的按钮
- python - Google OR-TOOLS VRP 以前的 OR-TOOLS 分配问题的问题
- postman - 如何在 Postman 中使用 pm.expect 断言来显示差异
- c++ - 使用 VSCode MACOS 构建时 GLFW 链接器命令失败(退出代码 1)
- reactjs - 如何记忆自定义钩子以提高性能
- javascript - 使用多个功能交换案例
- reactjs - React/Jest/Enzyme:在没有 Mocking 的情况下测试 useLocation Hook
- python - 使用 bbox_inches = 'tight' 时的 Matplotlib 缓冲区问题
- excel - 我似乎无法指定执行宏的工作表。无论我做什么,我都会收到错误 9