如何在Powershell中转换为JSON时更改选项卡宽度

如何在Powershell中转换为JSON时更改选项卡宽度,json,powershell,powershell-4.0,Json,Powershell,Powershell 4.0,我正在Powershell中创建一个JSON,我想在构建它时设置一个自定义选项卡宽度(而不是默认的4个空格,我只想设置2个空格) 我这样做是因为: 实际的JSON(不是下面示例中显示的JSON)非常大(100k+行),如果没有归档,它的大小非常大;如果我减少标签宽度,那么尺寸的减少是显著的 实际的JSON有5+个节点的深度 我不能使用-Compress,因为JSON需要可读 是的,我同意,如果存档,它的大小会大大减小,但我也需要它不存档 示例代码: $object = New-Object

我正在Powershell中创建一个JSON,我想在构建它时设置一个自定义选项卡宽度(而不是默认的4个空格,我只想设置2个空格)

我这样做是因为:

  • 实际的JSON(不是下面示例中显示的JSON)非常大(100k+行),如果没有归档,它的大小非常大;如果我减少标签宽度,那么尺寸的减少是显著的
  • 实际的JSON有5+个节点的深度
  • 我不能使用-Compress,因为JSON需要可读
  • 是的,我同意,如果存档,它的大小会大大减小,但我也需要它不存档
示例代码:

$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name Phone -Value "SomePhone"
Add-Member -InputObject $object -MemberType NoteProperty -Name Description -Value "Lorem ipsum dolor.."
Add-Member -InputObject $object -MemberType NoteProperty -Name Price -Value 99.99

$object | ConvertTo-Json
制表符宽度为4个空格字符的结果

我尝试过压缩,但它不能控制压缩级别(压缩的强度应该有多大)

结果明显压缩

我试图实现的是:制表符宽度=2个空格字符的结果

到目前为止,我尝试的是下面的伪代码。我仍然在这个圈子里。请带我离开那里:)


以下代码将缩进大小减半:

$json = @"
{
    "Phone":  "SomePhone",
    "Description":  "Lorem ipsum dolor..",
    "Price":  99.99
}
"@

($json -split '\r\n' |
% {
  $line = $_
  if ($_ -match '^ +') {
    $len  = $Matches[0].Length / 2
    $line = ' ' * $len + $line.TrimStart()
  }
  $line
}) -join "`r`n"

下面是一个简单的方法:

$data_json | convertto-json -depth 100 |
    foreach-object {$_ -replace "(?m)  (?<=^(?:  )*)", "`t" } |
    set-content 'output.json'
$data_json |转换为json-深度100|

foreach对象{$\-replace”(?m)(?)由于PowerShell的ConvertTo Json生成非确定性缩进,因此当前的答案不会生成数据结构中每个深度正好有两个空格的Json

要使每一级别的嵌套数据缩进到比封闭级别正好多两个空格的位置,需要重新生成缩进

在写下我自己的解决方案后,我在GitHub上发现了一个几乎相同的解决方案,来自Facebook的Daniel Lo Nigro(Daniel15)。这是一个可以接受管道输入的PowerShell函数。(我将正则表达式匹配做得更具体一些,以减少无意匹配数据的可能性。)


用法:
$foo | ConvertTo Json | Format Json

您可以将Newtonsoft.Json与PowerShell一起使用。您可以通过安装来方便地使用它

例如:

if (!(Get-Module -ListAvailable -Name "newtonsoft.json")) {
    Install-Module -Name "newtonsoft.json" -Scope CurrentUser -Force
}

Import-Module "newtonsoft.json" -Scope Local

$JObject = [Newtonsoft.Json.Linq.JObject]::new(
    [Newtonsoft.Json.Linq.JProperty]::new("Phone", "SomePhone"),
    [Newtonsoft.Json.Linq.JProperty]::new("Description", "Lorem ipsum dolor.."),
    [Newtonsoft.Json.Linq.JProperty]::new("Price", 99.99));

$JObject.ToString()
产生

{
  "Phone": "SomePhone",
  "Description": "Lorem ipsum dolor..",
  "Price": 99.99
}
在使用json时,它还有很多其他特性:

我使用了“更深层”(节点深度>=3)的json进行了测试,它似乎可以工作。谢谢!
while (1) {
    Google, StackOverflow
    Try Stuff found 
    Tweak stuff found

    if (Correct answer) {
        break
    }
}
$json = @"
{
    "Phone":  "SomePhone",
    "Description":  "Lorem ipsum dolor..",
    "Price":  99.99
}
"@

($json -split '\r\n' |
% {
  $line = $_
  if ($_ -match '^ +') {
    $len  = $Matches[0].Length / 2
    $line = ' ' * $len + $line.TrimStart()
  }
  $line
}) -join "`r`n"
$data_json | convertto-json -depth 100 |
    foreach-object {$_ -replace "(?m)  (?<=^(?:  )*)", "`t" } |
    set-content 'output.json'
# Formats JSON in a nicer format than the built-in ConvertTo-Json does.
function Format-Json([Parameter(Mandatory, ValueFromPipeline)][String] $json) {
    $indent = 0;
    ($json -Split "`n" | % {
        if ($_ -match '[\}\]]\s*,?\s*$') {
            # This line ends with ] or }, decrement the indentation level
            $indent--
        }
        $line = ('  ' * $indent) + $($_.TrimStart() -replace '":  (["{[])', '": $1' -replace ':  ', ': ')
        if ($_ -match '[\{\[]\s*$') {
            # This line ends with [ or {, increment the indentation level
            $indent++
        }
        $line
    }) -Join "`n"
}
if (!(Get-Module -ListAvailable -Name "newtonsoft.json")) {
    Install-Module -Name "newtonsoft.json" -Scope CurrentUser -Force
}

Import-Module "newtonsoft.json" -Scope Local

$JObject = [Newtonsoft.Json.Linq.JObject]::new(
    [Newtonsoft.Json.Linq.JProperty]::new("Phone", "SomePhone"),
    [Newtonsoft.Json.Linq.JProperty]::new("Description", "Lorem ipsum dolor.."),
    [Newtonsoft.Json.Linq.JProperty]::new("Price", 99.99));

$JObject.ToString()
{
  "Phone": "SomePhone",
  "Description": "Lorem ipsum dolor..",
  "Price": 99.99
}