0

Problem

At http://regex101.com, it is said that '$ will return a portion of the source string that follows the match. Yet it doesn't work like this for me.

Example

For example, I need to replace text in JSON. I need to remove some text from JSON after certain parameters.

 "ReportPackage": {
        "$id": "some id",
        "$type": "stuff",
        "ConnectionString": "REPLACE_HERE",
        "FtpConfiguration": {
            "$id": "some id",
            "$type": "some type",
            "Address": "some adress",
            "Password": "REPLACE_HERE",
            "Username": "REPLACE_HERE",
            "BaseDirectory": "some path"
        },
        "PgConnectionString": "REPLACE_HERE"
    }
},
"CurrentFederation": "",
"CurrentVirtualHost": "/",
"PgConnectionString": "REPLACE_HERE",
"PeriodicContinuationActivated": true

I need to replace the values ​​marked as REPLACE_HERE. I can use four separate regexes but I want to use single one(if possible).

My Attempt to Solve the Problem

I use this regex $'((("Password")|("ConnectionString")|("PgConnectionString")|("Username")))(.*), yet it doesn't work as I imagined is would. What did I do wrong?

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
DerzkeyBK
  • 165
  • 1
  • 9
  • 3
    why not just parse the json using an existing parser? Far easier than freaking around with regex. – MakePeaceGreatAgain Jun 18 '21 at 12:09
  • 3
    You misunderstood the [.NET regex reference](https://learn.microsoft.com/en-us/dotnet/standard/base-types/substitutions-in-regular-expressions). In fact, it should be used in the replacement pattern, see "*`$'` Includes all the text of the input string after the match in the replacement string*" – Wiktor Stribiżew Jun 18 '21 at 12:13
  • Does that mean that i should create class, then deserealize in class that i created, then change necessary values, then deserialize it. Is it far easier? – DerzkeyBK Jun 18 '21 at 12:14
  • 2
    You cannot manipulate a JSON string with regex *safely*, or *without assumptions*. With assumptions, you could try `Regex.Replace(text, @"(?m)^(\s*""(?:Password|ConnectionString|PgConnectionString|Username)""\s*:\s*"")[^""]+", "$1")`. – Wiktor Stribiżew Jun 18 '21 at 12:15
  • No, it is not a matter of being easier or harder. It is a matter of being sure the replacements are done always reliable. And if `"$type": "some text that that matches your regex", ` you will have a problem. – Cleptus Jun 18 '21 at 12:20
  • @WiktorStribiżew that worked thanks. @Cleptus i`ll discuss this with my teamlead, thanks for the thought. – DerzkeyBK Jun 18 '21 at 12:26

1 Answers1

3

You misunderstood the .NET regex reference. In fact, $' is a valid substituion pattern, and it cannot be used to do what you want in the regex pattern.

$'   Includes all the text of the input string after the match in the replacement string.

In your $'((("Password")|("ConnectionString")|("PgConnectionString")|("Username")))(.*), pattern, $ simply requires the end of string position and since there are more patterns after $, the regex will never match any string.

More, JSON strings cannot be safely manipulated with regex without assumptions.

If your values do not contain double quotes, and if the JSON string is indented the way you showed you could try

Regex.Replace(text, @"(?m)^(\s*""(?:Password|ConnectionString|PgConnectionString|Username)""\s*:\s*"")[^""]+", "$1")

where

  • (?m) - makes ^ match start of line positions
  • ^ - start of a line
  • (\s*""(?:Password|ConnectionString|PgConnectionString|Username)""\s*:\s*"") - Group 1 that captures
    • \s* - zero or more whitespaces
    • " - a " char
    • (?:Password|ConnectionString|PgConnectionString|Username) - one of the strings listed
    • "\s*:\s*" - ", a : enclosed with zero or more whitespaces and then a "
  • [^"]+ - one or more chars other than ".

The $1 replacement pattern replaces the matches with Group 1 value.

See the regex demo.

To do that properly, parse JSON string and clear out the key values you need. See How can I parse JSON with C#?

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563