skip to Main Content

I get a response from the backend as text in which I have to find a match for numbers which is minimum 16 digits in length.

Let’s say I have data something like this:

{"BIG_INT": 123456789012345675,"BIG_INT_ARRAY_SINGLE": [123456789012345676],"BIG_INT_ARRAY_MULTIPLE": [123456789012345661,12345678901234562,12345678901234563,12345678901234564],"STRING_BIG_INT_ARRAY": "[12345678901234567,12345678901234567, 12345678901234567,12345678901234567]","STRING_BIG_INT":"12345678901234567","BIG_INT_FLOATING_DECIMAL": 12345678901234567.76543210987654321}

There are certain conditions where it should not match a number:

  1. If the number is enclosed within double quotes:
    ("STRING_BIG_INT":"12345678901234567")`
  2. If the numbers are within string enclosed array:
    "STRING_BIG_INT_ARRAY":"[12345678901234567,12345678901234567]"
  3. If the number is fractional:
    "BIG_INT_FLOATING_DECIMAL":12345678901234567.76543210987654321

Conditions where it should match a number:

  1. If it’s an integer "BIG_INT": 123456789012345675, here value 123456789012345675 should get matched.
  2. If it’s inside an array "BIG_INT_ARRAY_MULTIPLE":[123456789012345678,123456789012345678] here these two numbers should be matched separately.

I tried this regular expression -> (:s*)([[])?(d{16,})(s*)([,}]])

One con in this expression is if we have a array of numbers
"test":[12345678901234567,1236543858688483444,26531562351351374343], here my expression only matches the first number. I wanted to match all the numbers inside the array if the array is not enclosed by double quotes.

After matching all numbers, I have code like this to replace numbers to a BigInteger formate(Ex:"16536235653725645345n") and I extract the value part of it and convert the number to a BigInteger.

const bigNumsRegExp = new RegExp(/(:s*)([[])?(d{16,})(s*)([,}]])/g);
`const serializedData = data.replace(bigNumsRegExp, '$1$2"$3n"$4$5');`

So I only wanted a regular Expression which match numbers only from BIG_INT,BIG_INT_ARRAY_SINGLE and BIG_INT_ARRAY_MULTIPLE

Any help from anyone is appreciated.

Thanks

2

Answers


  1. Here’s a JSON reviver that parses https://tsplay.dev/wXyloN

    function JsonParseWithBigints(json: string) {
      const g = /bd+(.d+)?b/g;
      let matches = s.match(g) ?? []
      return JSON.parse(s, (key, value) => {
        if (typeof value === 'number') {
          let s = matches.shift()!
          if (+s !== value) throw new Error(s + '!=' + value)
          if (s === `${value}`) return value;
          if (!s.includes('.')) {
            return BigInt(s)
          }
          let [d, f] = s.split('.')
          return { value: BigInt(d + f), exp: -f.length }
        }
        if (typeof value === 'string') {
          for (let k of value.match(g) ?? []) {
            let s = matches.shift()!
            if (s !== k) throw new Error(s + '!=' + value)
          }
        }
        return value
      })
    }
    

    It parses JSON while replacing the numbers that would lose precision while parsing with their BigInt variant taken from the original string

    Here’s what it produces for your input:

    {
      "BIG_INT": 1123456789012345675n,
      "BIG_INT_ARRAY_SINGLE": [
        2123456789012345676n
      ],
      "BIG_INT_ARRAY_MULTIPLE": [
        3123456789012345661n,
        412345678901234562n,
        512345678901234563n,
        612345678901234564n
      ],
      "STRING_BIG_INT_ARRAY": "[712345678901234567,812345678901234567, 912345678901234567,1012345678901234567]",
      "STRING_BIG_INT": "1112345678901234567",
      "BIG_INT_FLOATING_DECIMAL": {
        "value": 121234567890123456776543210987654321n,
        "exp": -17
      }
    }
    
    Login or Signup to reply.
  2. Nothing complicated since JSON has a very limited number of types:

    • put what you need to preserve in a capture group (strings and floats, numbers with exponant)
    • test if the capture group exists in the replacement arrow function and choose what to return.

    Example that put double-quotes around integers (when needed):

    let source = `{
      "BIG_INT": 123456789012345675,
      "BIG_INT_ARRAY_SINGLE": [123456789012345676],
      "BIG_INT_ARRAY_MULTIPLE": [123456789012345661,12345678901234562,12345678901234563,12345678901234564],
      "STRING_BIG_INT_ARRAY": "[12345678901234567,12345678901234567, 12345678901234567,12345678901234567]",
      "STRING_BIG_INT":"12345678901234567",
      "BIG_INT_FLOATING_DECIMAL": 12345678901234567.76543210987654321
    }`;
    
    const pattern = /("[^\"]*(?:\.[^\"]*)*"|d+.d*(?:e[-+]?d+)?|d+(?:e[-+]?d+))|d+/gi;
    
    let result = source.replace(pattern, (m, g1) => g1 ? g1: `"${m}"`);
    
    console.log(result);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search