【问题标题】:输入特定值时如何过滤输入值
【发布时间】:2022-01-23 13:22:39
【问题描述】:

我需要监听输入并动态获取其值,当碰巧输入了特定的“标志”时,获取接下来输入的任何内容,直到再次出现标志。

让我解释一下:

假设我有一个“标志”数组

let flags = ['foo','bar','baz']

我有一个输入要听,它给了我以下字符串(动态,逐个字符):

let input = "whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen"

*foobar 出现两次,baz 出现一次

我想以某种方式创建,也许是这样的对象:

{
foo: ["david","john"],
bar: ["jennifer-andrew-bill","christen"],
baz: ["eric"]
}

或 3 个单独的数组,我并不关心结构,只要我正确过滤值即可

【问题讨论】:

  • 用数组中的元素分割字符串。并将其分组。

标签: javascript arrays json object ecmascript-6


【解决方案1】:

@Apple BS 的好回答,我只想提出这种语法:

const flags = ['foo', 'bar', 'baz']
const str = 'whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen'
const strSplit = str.split(new RegExp(`(${flags.join('|')})`, 'g'))
const obj = Object.fromEntries(flags.map(f => [f, []]))

strSplit.forEach((el, i) => {
  if (flags.includes(el)) obj[el].push(strSplit[i + 1])
})

console.log(obj)

编辑:

还有一个使用正则表达式捕获组的版本。

const flags = ['foo', 'bar', 'baz']
const str = 'whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen'
const obj = Object.fromEntries(flags.map(f => [f, []]))
const fRe = flags.join('|'), regex = new RegExp(`(${fRe})(.*?)(?=${fRe}|$)`, 'g')

for (const match of str.matchAll(regex)) obj[match[1]].push(match[2])

console.log(obj)

【讨论】:

  • 迄今为止最易读的
【解决方案2】:

首先,构造一个正则表达式:

let regex = '('; // parenthesis is added for capturing groups, which means the flags will be captured too
for (f of flags) regex += f + '|';
regex = new RegExp(regex.substring(0, regex.length - 1) + ')', 'g'); // construct the regex with global flag
// regex = /(foo|bar|baz)/g

然后,拆分字符串:

s = s.split(regex) // ["whateveridontneedthat", "foo", "david", "bar", "jennifer-andrew-bill", "baz", "eric", "foo", "john", "bar", "christen"]

最后,遍历分割后的字符串并将它们添加到对象中。

以下是完整示例:

let flags = ['foo', 'bar', 'baz'];
let s = "whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen";
let regex = '(';
let obj = {};
for (f of flags)  regex += f + '|';
regex = new RegExp(regex.substring(0, regex.length - 1) + ')', 'g');
s = s.split(regex);

for (let i = 0; i < s.length; i++) {
  for (let j = 0; j < flags.length; j++) { // checking for flags
    if (s[i] == flags[j]) { // found the flag
      if (flags[j] in obj) obj[flags[j]].push(s[i + 1]); // array exist in object
      else obj[flags[j]] = [s[i + 1]]; // create array in object
      i++; // skip next s[i]
      break; // s[i] can only be one of the flag
    }
  }
}
console.log(obj);

【讨论】:

  • 只是对 OP 的提醒。如果有两个连续的标志,它将产生一个空字符串。您也可以自己处理这种极端情况。
  • @ikhvjs 很好,它处理它就像我希望它处理它一样,但是好的一点,在不同的情况下,我可能需要跳过它并只推送那些不为空的,我会尝试修改它,谢谢
【解决方案3】:

在@AppleBS 和@Jean Will 的回答之上,

只需简化 for 循环。

const flags = ["foo", "bar", "baz"];
const str =
    "whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen";
const strSplit = str.split(new RegExp(`(${flags.join("|")})`, "g"));

const output = strSplit.reduce((carry, item, idx, arr) => {
    if (idx !== 0) {
        if (idx % 2 === 0) carry[arr[idx - 1]].push(item);
        else if (!carry[item]) carry[item] = [];
    }
    return carry;
}, {});

console.log(output);

【讨论】:

    猜你喜欢
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    相关资源
    最近更新 更多