最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Edit json file values with Powershell - Stack Overflow

programmeradmin5浏览0评论

The JSON file structure looks like below. I want to change the points value with PowerShell. In id 1, it should be a positive value, 48-35 = output 13, and in id 2, it should be a negative value, 31-33 = output -2.

How to do it?

{
  "disciplin": [
    {
      "name": "Playoff",
      "teamsize": 2,
      "gender": 3,
      "system": 32,
      "status": 2,
      "id": 1
      ,
      "games": [
        {
          "result": "4:0",
          "points": "48:35",
          "id": 1
        },
        {
          "result": "4:0",
          "points": "31:33",
          "id": 2
        },
      ]
      ,
    },
  ]
}

I tried this ps1 script in PowerShell 7.5.0, but nothing changes in the output file. It's all the same as the original file.

($json = Get-Content -Raw C:\Users\[USER]\Documents\file.json | ConvertFrom-Json)

$json -replace '(?<="points":\s*")(\d+):(\d+)(?=")', 
               { [int] $_.Groups[1].Value - $_.Groups[2].Value }

$json | ConvertTo-Json -depth 8 |Out-File "C:\Users\[USER]\Documents\new.json"

The JSON file structure looks like below. I want to change the points value with PowerShell. In id 1, it should be a positive value, 48-35 = output 13, and in id 2, it should be a negative value, 31-33 = output -2.

How to do it?

{
  "disciplin": [
    {
      "name": "Playoff",
      "teamsize": 2,
      "gender": 3,
      "system": 32,
      "status": 2,
      "id": 1
      ,
      "games": [
        {
          "result": "4:0",
          "points": "48:35",
          "id": 1
        },
        {
          "result": "4:0",
          "points": "31:33",
          "id": 2
        },
      ]
      ,
    },
  ]
}

I tried this ps1 script in PowerShell 7.5.0, but nothing changes in the output file. It's all the same as the original file.

($json = Get-Content -Raw C:\Users\[USER]\Documents\file.json | ConvertFrom-Json)

$json -replace '(?<="points":\s*")(\d+):(\d+)(?=")', 
               { [int] $_.Groups[1].Value - $_.Groups[2].Value }

$json | ConvertTo-Json -depth 8 |Out-File "C:\Users\[USER]\Documents\new.json"
Share Improve this question edited Mar 23 at 10:35 Mark Rotteveel 110k229 gold badges156 silver badges224 bronze badges asked Mar 22 at 21:29 AndersAnders 1137 bronze badges 3
  • I did a try with help from your post. The script runs without errors but nothing changes in the output file. It just look the same as the input json i want to change. – Anders Commented Mar 23 at 5:39
  • You mistakenly mixed the two alternative approaches shown in my answer - you must choose one or the other. Please see the new bottom section of the answer, which spells out file-based solutions for both approaches. Also note that I've modified the regex to make the string replacement to turn the property value from a string JSON value - e.g. "48:35" - to a number - e.g. 13, i.e. unquoted; however, if you want to keep the result as string (e.g., "13"), you can use the original regex (still mentioned in the updated answer; in the OO approach, remove the outer [int] cast). – mklement0 Commented Mar 23 at 16:48
  • My answer now provides two alternative solutions to your problem and discusses the pros and cons of each. Because it isn't clear from the question whether you want the transformed value to be a JSON number rather than a string, a number is assumed, along with instructions on how to alternatively get a string. The answer also spells out both solutions in the context of updating a JSON file in-place - even though that wasn't part of your original question, and only came into play because you misapplied the solution alternatives. Let us know if something is still missing from the answer. – mklement0 Commented Mar 24 at 10:57
Add a comment  | 

1 Answer 1

Reset to default 0

Preface

  • The solution attempt you later edited into your question is based on a mistaken interpretation of the solutions below, inappropriately mixing an OO-based approach via ConvertFrom-Json with a plain-text approach based on string replacements only.

  • While incidental to the question as asked, the bottom section now spells out both approaches in the context of in-place updating of a given JSON file, which seems to be your ultimate goal.


As noted in the answers to your previous question, it is generally better for robustness to use OO processing based on a JSON parser, namely ConvertFrom-Json, and later reconversion to JSON with ConvertTo-Json.

In a pinch, you can use plain-text processing with a regex-based string replacement via the -replace operator even on your entire JSON document, as shown below; alternatively, use the - more verbose but more robust - OO approach and apply the string replacement only to the property values of interest, analogously - see the next section.

Assuming that your JSON document is stored in variable $json (to read it from a file, use something like $json = Get-Content -Raw file.json):

  • A PowerShell (Core) 7 solution:
$json -replace '(?<="points":\s*)"(\d+):(\d+)"', 
               { [int] $_.Groups[1].Value - $_.Groups[2].Value }

  • In Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1), direct use of .NET APIs is needed (works in PowerShell 7 too):
[regex]::Replace(
  $json,
  '(?<="points":\s*)"(\d+):(\d+)"',
  { param($m) [int] $m.Groups[1].Value - $m.Groups[2].Value }
)

Note:

  • For an explanation of the regex part and the option to experiment with it, see this regex101 page (the linked page uses an equivalent C# verbatim string).

  • To learn more about the script block-based ({ ... }) string-replacement technique, see this answer.

  • The above replaces the string property values (e.g. "48:35") with numeric ones (e.g. 13). If you want the new values to be strings too, use the following regex instead:
    '(?<="points":\s*")(\d+):(\d+)(?=")'
    In the OO solution below, remove the [int] cast.


OO solution, for PowerShell (Core) 7 (adaptable to Windows PowerShell analogous to the above):

ConvertFrom-Json $json |
  ForEach-Object {
    $_.disciplin.games | 
      ForEach-Object {
        $_.points = 
          [int] $_.points -replace '(\d+):(\d+)', 
                             { [int] $_.Groups[1].Value - $_.Groups[2].Value }
      }
    $_ # Output the modified object.
  } |
  ConvertTo-Json -Depth 4

Note:

  • -Depth 4 is needed to prevent truncation of the object graph in the to-JSON conversion; if your real JSON is more deeply nested, increase the number as needed - see this post for background information.

Complete, file-based solutions that update the input file in place and work in both PowerShell editions:

  • Plain-text solution:
$file = "$HOME\Documents\file.json"
[regex]::Replace(
  (Get-Content -Raw $file),
  '(?<="points":\s*)"(\d+):(\d+)"', 
  { param($m) $m.Groups[1].Value - $m.Groups[2].Value }
) | Set-Content -Encoding utf8 $file
  • OO solution:
$file = "$HOME\Documents\file.json"
(Get-Content -Raw $file) | 
  ConvertFrom-Json |
  ForEach-Object {
    $_.disciplin.games | 
      ForEach-Object {
        $_.points = 
          [int] [regex]::Replace(
            $_.points,
            '(\d+):(\d+)', 
            { param($m) [int] $m.Groups[1].Value - $m.Groups[2].Value }
          )          
      }
    $_ # Output the modified object.
  } |
  ConvertTo-Json -Depth 8 |
  Set-Content -Encoding utf8 $file
发布评论

评论列表(0)

  1. 暂无评论