繁体   English   中英

使用来自 PowerShell 的注释转换为 JSON

[英]Convert to JSON with comments from PowerShell

我有一个非常简单的 json,这段代码适用于他:

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

但是,如果我的 json 有任何评论// wololo它会中断。 让这个解析器接受评论会不会太难了?

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

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

另一个答案中的解决方案仅删除// comments位于行首(带或不带空格)的/* multiline comments */ ,而不会删除/* multiline comments */

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

$configFile = (Get-Content path-to-jsonc-file -raw)
# Keep reading, for an improvement
# $configFile = $configFile -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/'

正如@Jiří Herník 在他的回答中指出的那样,这个表达式没有考虑到其中包含注释的字符串的情况,例如"url": "http://mydomian.com" 要处理这种情况:

$configFile = $configFile -replace '(?m)(?<=^([^"]|"[^"]*")*)//.*' -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}"
        }
      } ,
      {
        "Args": {
          "serverUrl": "http://localhost:5341"
        }
      }
    ]
  }
}

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

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

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

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

重要的提示:

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

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

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

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

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

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

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

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

我写了一个函数,它接受任何评论,如果找到,就把它们放回 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM