skip to Main Content

I want to parse some data that’s in a string format. Anything enclosed in parenthesis in the string to parse should be replaced with itself run through a function. This is what I want:

function foo(str) {
    return parseInt(str) + 1; // Example function, not actually what the function will be
}

function parse(str) {
    // everything in str that is enclosed in parenthesis should be replaced with itself ran through foo();

    // Example
    // Input: "My name is foo and I am (0) year old."
    // Output: "My name is foo and I am 1 year old."
    // "(0)" has been replaced with the result of foo("0")
}

I have thought up a couple bad workarounds, but I want something more robust. For example:

function parse(str) {
    // Input: "My name is foo and I am (0) year old."
    str = str.replaceAll("(", "${foo('");
    str = str.replaceAll(")", "')}");
    str = "`" + str + "`"
    // Here str will be "`My name is foo and I am ${foo(0)} year old.`"
    // And I can use eval() or something to treat it like I've typed that
}

This, however, is kind of a bad way of doing it.
EDIT: I tested it, it works, but it is quite vulnerable.

I can’t think of anything else and I’m not very good with RegEx. (although I’d accept a solution using it)

3

Answers


  1. You could used a full matching pattern, and wrap the resulting string in back-ticks so it’s evaluated as a string literal.

    const foo = (value) => +value + 1;
    
    const parse = (str) =>
      '`' +
      str.replace(/((w+))/g, (_, v) => `${foo(${v})}`) +
      '`';
    
    // Source: https://stackoverflow.com/a/29182787/1762224
    console.log(eval(parse('My name is foo and I am (0) year old.')));

    The only problem with this is that the pattern to match between the parenthesis seems to be any kind of value. This could pose problems down the road. Just tweak the regular expression as-needed.


    If you don’t want to use eval, pass a callback:

    const foo = (value) => +value + 1;
    
    const parse = (str, callback) =>
      str.replace(/((w+))/g, (_, v) => callback(v));
    
    // Source: https://stackoverflow.com/a/29182787/1762224
    console.log(parse('My name is foo and I am (0) year old.', foo));
    Login or Signup to reply.
  2. Here’s what I would do. I would match the string with a RegEx that would match anything inside parenthesis in the string. With that, I would then use str.replaceAll() to replace the matched string with the result of the foo() function.

    const regex = /((d*))/gm;
    
    function foo(str) {
        return parseInt(str) + 1;
    }
    
    function parse(str) {
      
      // Loop all match the regex find in the string
      let m;
      while ((m = regex.exec(str)) !== null) {
        
        // This is necessary to avoid infinite loops with zero-width matches
        if (m.index === regex.lastIndex) {
            regex.lastIndex++;
        }
        
        // Replace all instance of the match with the operation of the match
        str = str.replaceAll(m[0], foo(m[1]))
      }
      return str;
    }
    
    let p = parse('My name is foo and I am (0) year old and I want (54) apples');
    
    // The result will be: My name is foo and I am 1 year old and I want 55 apples
    

    With that, you won’t need to use eval() as it potentially pose a risk for your application.

    I hope that would work for you. If I missed anything, tell me, I will edit my answer.

    Login or Signup to reply.
  3. See if it works for you:

    function foo(str) {
      return parseInt(str) + 1;
    }
    
    function parse(str) {
      return str.replace(/((d+))/g, (_, num) => foo(num));
    }
    

    This Regex pattern matches every number in a string that is inside a parenthesis, put them in the 1st capturing grouping and pass all of them in foo().

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search