-1

I am having users enter a JSON object into a text field and want to check to make sure it has a similar format to this:

{
    "address": "some string",
    "msg": "some string",
    "sig": "some string",
    "version": "some string"
}

I want it to start with { and end with } and check for "address", "msg", "sig", and "version".

So far I have this which works if it's in that exact format:

^{.*"address".+,.*"msg".+,.*"sig".+,.*"version".+}$

However, I would like the keys to be valid in any order. From my understanding, (?=) is used to search a forward looking string, I've tried the following and it doesn't seem to work....

^{.*(?="address".+,)(?="msg".+,)(?="sig".+,)(?="version".+).*}$

What am I getting wrong here?

Jack Hanna
  • 169
  • 2
  • 3
  • 15
  • 1
    I’d personally `JSON.parse` the string and validate against the JS object instead of using regex to solve the problem. Just some thoughts. – hackape Jan 18 '23 at 01:56
  • 1
    May I ask why are you trying to solve this with regex? Wouldn't it be easier to first try to parse it as JSON with `JSON.parse()`, you will know if it's a valid JSON this way and catch the error if it isn't and then just check if your keys are inside of it? – SnoopFrog Jan 18 '23 at 01:57
  • Thanks @blhsing, but I've already seen those 2 posts and referenced them to come up with the above. I hadn't thought about using JSON.parse, I'm going to see if that is feasible. – Jack Hanna Jan 18 '23 at 02:03
  • 2
    If you compared those two posts with what your wrote, you'd notice that they have `.*` before *each* sub-pattern to allow them to be matched in any position of the string, and yours doesn't. – blhsing Jan 18 '23 at 02:05

1 Answers1

0

As @blhsing pointed out, I was missing .* between each of the middle contain searched. This now works:

^{.*(?=.*"address".+,)(?=.*"msg".+,)(?=.*"sig".+,)(?=.*"version".+).*}$

However, as the comments suggested it would be better to solve this using JSON.parse(), which is what I ended up doing as it's a more robust solution:

const signedMsg = document.getElementById("signedMsg").value;
const correctFormat = signedMsg.includes(`{`) && 
                      signedMsg.includes(`"address"`) && 
                      signedMsg.includes(`"msg"`) && 
                      signedMsg.includes(`"sig"`) && 
                      signedMsg.includes(`"version"`) && 
                      signedMsg.includes(`}`);
let validJSON = false;
try {
  let test = JSON.parse(signedMsg);
  valid = true;
} catch {};

if (validJSON && correctFormat) {
  // do stuff
}
Jack Hanna
  • 169
  • 2
  • 3
  • 15
  • 1
    That's not what I meant when I said having `.*` before each sub-pattern. What I meant is like `(?=.*"address")(?=.*"msg")`, which you can see from those two posts I linked to. – blhsing Jan 18 '23 at 02:23
  • Thanks @blhsing, just updated it with your correction – Jack Hanna Jan 18 '23 at 05:44