【问题标题】:JS object/JSON key wildcardJS 对象/JSON 键通配符
【发布时间】:2021-08-06 10:27:38
【问题描述】:

我有一个从 JSON 评估的对象,如下所示:

{
    "foo %s": "bar %s",
    "Hello %s world %s.": "We have multiple %s %s."
}

使用这个对象和以下输入,我试图实现这样的目标:

  • foo bar -> 匹配 foo %s -> bar bar
  • Hello foo world bar. -> 匹配 Hello %s world %s. -> We have multiple foo bar

到目前为止,我有以下代码适用于一个 %s,并且仅当它被空格包围时。

let str = "input here";
let a = {
        "foo %s": "bar %s",
        "Hello %s world %s.": "We have multiple %s %s."
    },
    p = str.split(" "),
    result;
for (let j in p) { // loop indices
    let pp = p.map(u => u); // create local array
    pp[j] = "%s"; //replace index with %s
    if (a[pp.join(" ")]) { // check if this is in the object
        result = a[pp.join(" ")].replace("%s", p[j]); // join the array and replace %s from the result
        break;
    }
}

有什么想法或建议吗?

【问题讨论】:

    标签: javascript json dictionary object


    【解决方案1】:

    您可以将对象转换为regular expressions,然后再转换为execute them in a call to String.prototype.replace

    单个定义的替换操作示例:

    console.log('Hello foo world bar.'.replace(/^Hello (.*?) world (.*?) bar\.$/, 'We have multiple $1 $2.'))
    // Output: We have multiple foo bar.
    

    这里我们基本上匹配整个字符串 - 如果匹配模式,整个内容将被替换。

    如您所见,要实现此目的,您需要将"Hello %s world %s." 转换为/^Hello (.*?) world (.*?)\.$/(.*?) 定义一个包含任何字符的非贪婪捕获组)并将"We have multiple %s %s." 转换为@987654329 @($x 指的是x-th 捕获组的内容)。

    所以你可以有这样的功能:

    function replaceTemplates (str, templates) {
      // This helper function escapes any characters which would have a special
      // meaning in the regexp otherwise. $& is the match as a whole, so it replaces
      // each of these characters with themselves prepended by a backlash.
      const escapeRegExp = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
      
      for (const [template, replacement] of Object.entries(templates)) {
        // We create a regexp from the template, replacing every %s with (.*?), wrapping it
        // in ^ and $ (start/end of string) and escaping all the other special characters.
        const re = new RegExp('^' + escapeRegExp(template).replace(/%s/g, '(.*?)') + '$')
        
        if (re.test(str)) {
          // To get the correct string for the right side of the string replace method,
          // we have to replace each %s in the replacement string by $1, $2, $3 etc. and
          // also replace single $ signs by $$ because the $ has a special meaning as shown
          // above, and then we can call the actual replace and return the result. But since
          // a $ in the replacement has to be escaped as just explained, we have to write
          // FOUR $ signs to get TWO at the end.
          let i = 1 // This is used as counter in the following replacing operations for $x
          const reReplacement = replacement
            .replace(/\$/g, '$$$$')
            .replace(/%s/g, () => '$' + i++) // By using a function, we can make $x dynamic
          
          return str.replace(re, reReplacement)
        }
      }
      
      return str
    }
    
    const templates = {
      'foo %s': 'bar %s',
      'Hello %s world %s.': 'We have multiple %s %s.'
    }
    
    console.log(replaceTemplates('foo bar', templates)) // Output: bar bar
    console.log(replaceTemplates('Hello foo world bar.', templates)) // Output: We have multiple foo bar.

    顺便说一句:如果pp = p.map(u => u) 应该创建一个副本,我建议pp = p.slice() 或只是pp = [...p]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 2011-01-16
      • 1970-01-01
      • 2023-01-28
      • 1970-01-01
      相关资源
      最近更新 更多