使用PowerShell的注释转换为JSON

时间:2018-06-27 15:53:35

标签: json powershell

我有一个非常简单的json,下面的代码对他有用:

function Get-CustomHeaders() {
   return Get-Content -Raw -Path $JsonName | ConvertFrom-Json
}

但是,如果我的json有任何评论// wololo,它就会中断。使此解析器接受注释是否太难了?

5 个答案:

答案 0 :(得分:6)

在转换前从输入中删除注释行:

(Get-Content $JsonName) -replace '^\s*//.*' | Out-String | ConvertFrom-Json

答案 1 :(得分:1)

这里有一个示例,以前的答案无法正确处理:

{
"url":"http://something" // note the double slash in URL
}

所以这是正则表达式,它也解决了这个问题。

$configFile = $configFile -replace '(?m)(?<=^([^"]|"[^"]*")*)//.*' -replace '(?ms)/\*.*?\*/'

重要说明:

Powershell 6.0+ 可以加载带有注释的JSON。

答案 2 :(得分:0)

另一个答案中的解决方案仅将// comments删除在行的开头(带空格或不带空格),而不删除/* multiline comments */

此代码删除了所有类型的///* multiline comments */ /

$configFile = (Get-Content path-to-jsonc-file -raw)
$configFile = $configFile -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/'

例如该文件中的所有注释:

{
  // https://github.com/serilog/serilog-settings-configuration
  "Serilog": {
    "MinimumLevel": "Error", // Verbose, Debug, Information, Warning, Error or Fatal
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "D:\\temp\\MyService\\log.txt",
          "rollingInterval": "Day",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] ({App}) ({Environment}) {Message:lj}{NewLine}{Exception}"
        }
      } /*,
      {
        "Name": "Seq",
        "Args": {
          "serverUrl": "http://localhost:5341"
        }
      }*/
    ]
  }
}

结果:

{
  "Serilog": {
    "MinimumLevel": "Error",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "D:\\temp\\MyService\\log.txt",
          "rollingInterval": "Day",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] ({App}) ({Environment}) {Message:lj}{NewLine}{Exception}"
        }
      }
    ]
  }
}

答案 3 :(得分:0)

捕获字符串、转义符和注释的所有组合的更简单的模式是:

$configFile = $configFile -replace '("(\\.|[^\\"])*")|/\*[\S\s]*?\*/|//.*', '$1';

这假定文件是有效的,没有未关闭的字符串或注释。如果这个问题,无效文件超出了范围。

第一部分 ("(\\.|[^\\"])*") 匹配完整字符串并跳过任何转义字符,包括 \\\"。这会被捕获,以便将其放回替换字符串中。

第二部分 /\*[\S\s]*?\*/ 匹配多行注释。它使用 [\S\s] 而不是 .,因此也匹配换行符。它是非空白字符 (\S) 和空白字符 (\s) 的组合。 *? 是一个懒惰的重复,所以它会尽可能少地匹配,所以它不会跳过任何结束的 */

最后一部分 //.* 匹配单行注释。 . 不会匹配任何换行符,因此它只会匹配到行尾。

当一个字符串被匹配时,它被捕获到槽 1 中。当一个注释被匹配时,什么都不会被捕获。替换为插槽 1 ($1) 中的任何内容。结果是字符串匹配但保留,但注释被删除。

答案 4 :(得分:0)

我编写了一个函数,可以接收任何注释,如果找到,会将它们放回 JSON 文件中。

这也允许读取和写入 JSON 文件。

里面有评论。在 v5.1 和 v7 中测试。

# Helper Function
# Write the contents of argument content to a file.
# Will create the file if it does not exist.
Function Write-ToFile {
  Param ([Parameter(Mandatory=$true, Position=0)] [string] $path,[Parameter(Mandatory=$true, Position=1)] [string] $content)
  [System.IO.File]::WriteAllText($path, $content)
}

Function Invoke-ReadWriteJSON {

  <#

  .SYNOPSIS
  Reads and writes properties from a JSON file.

  .DESCRIPTION
  This will allow JSON files to have comments, either multi-line or single line
  comments are supported.

  If the file does not exist or is empty then the default file contents are
  written to it.

  .NOTES
  Author: Ste
  Date Created: 2021.05.01
  Tested with PowerShell 5.1 and 7.1.
  Posted here: https://stackoverflow.com/questions/51066978/convert-to-json-with-comments-from-powershell

  .BUGS: NA

  .TODO: NA

  .PARAMETER filePath
  The file path of the JSON file.

  .PARAMETER Mode
  This parameter is either Read or Write.

  .PARAMETER Property
  The property of the JSON object.

  .PARAMETER newValue
  The new property of the JSON object.

  .INPUTS
  None. You cannot pipe objects to Add-Extension.

  .OUTPUTS
  Writes to or reads a file using the filePath parameter.

  .EXAMPLE (Write the property "Prop 1" with the value "Get in you machine!" to a file)
  PS> Invoke-ReadWriteJSON -filePath $jsonFilePath "Write" "Prop 1" "Get in you machine!"

  .EXAMPLE (Read a property from a file)
  PS> Invoke-ReadWriteJSON -filePath $jsonFilePath "Read" "Prop 2"
  PS> temp

  #>

  Param
  (
    [Parameter(Mandatory = $true, HelpMessage    = 'The file path of the JSON file.')]
    [String]$filePath,
    [Parameter(Mandatory = $true, HelpMessage    = 'This parameter is either Read or Write.')]
    [String]$Mode,
    [Parameter(Mandatory = $true, HelpMessage    = 'The property of the JSON object.')]
    [String]$Property,
    [Parameter(Mandatory = $false, HelpMessage   = 'The new property of the JSON object.')]
    [String]$newValue
    )

  # If there is a file then set its content else set the content variable to empty.
  if (Test-Path -LiteralPath $filePath) {
    $contents = Get-Content -LiteralPath $filePath
    $contents = $contents -replace '\s*' # Replace any whitespaces so that the length can be checked.
  }
  else {
    $contents = ''
  }

  # if the file does not exist or the contents are empty
  if ((Test-Path -LiteralPath $filePath) -eq $false -or $contents.length -eq 0) {
    Write-ToFile $filePath $jsonSettingFileDefaultContents
  }

  # This will allow single and multiline comments in the json file.
  # Regex for removing comments: https://stackoverflow.com/a/59264162/8262102
  $jsonContents = (Get-Content -LiteralPath $filePath -Raw) -replace '(?m)(?<=^([^"]|"[^"]*")*)//.*' -replace '(?ms)/\*.*?\*/' | Out-String | ConvertFrom-Json

  # Grab the comments that will be used late on.
  $jsonComments = (Get-Content -LiteralPath $filePath -Raw) -replace '(?s)\s*\{.*\}\s*'

  # Read the property.
  if ($Mode -eq "Read") {return $jsonContents.$Property}

  # Write the property.
  if ($Mode -eq "Write") {
    $jsonContents.$Property = $newValue
    $jsonContents | ConvertTo-Json -depth 32 | set-content $filePath
    # Trims any whitespace from the beginning and end of contents.
     Set-content $filePath ((Get-Content -LiteralPath $filePath -Raw) -replace '(?s)^\s*|\s*$')
  }

  # If there are comments then this section will add them back in. Important to
  # read contents with -Raw switch here.
  if ($jsonComments.length -gt 0) {
    $jsonNewcontents = (Get-Content -LiteralPath $filePath -Raw) -replace '(?m)(?<=^([^"]|"[^"]*")*)//.*' -replace '(?ms)/\*.*?\*/'
    # Trims any whitespace from the beginning and end of contents.
     Set-content $filePath (("$jsonComments`n" + $jsonNewcontents) -replace '(?s)^\s*|\s*$')
  }

}

$deskTopFolder = [Environment]::GetFolderPath("DesktopDirectory")
$jsonFilePath = "$deskTopFolder\color-dialog-settings.json"

$jsonSettingFileDefaultContents = @'
// Some comments go here.
// Some comments go here.
// Some comments go here.
{
  "Prop 1":  "temp",
  "Prop 2":  "temp"
}
'@

# Write the JSON property.
# Invoke-ReadWriteJSON -filePath $jsonFilePath "Write" "Prop 1" "Get in you machine!"

# Read the JSON property.
Invoke-ReadWriteJSON -filePath $jsonFilePath "Read" "Prop 2"
# PS> temp