【问题标题】:Javascript- Arrays with tokens that are a certain valueJavascript- 带有特定值标记的数组
【发布时间】:2024-01-16 02:49:01
【问题描述】:

假设我有一个数组['dcab', 'feac', 'gwad', 'dnae'],但希望使每个'a' 都在自己的令牌中,例如['dc', 'a', 'b', 'fe', 'a', 'c', 'gw', 'a', 'd', 'dn', 'a', 'e'];。我该怎么做?谢谢!

【问题讨论】:

  • 嗯?你是怎么得到这个结果的?你怎么知道在哪里拆分它?为什么有些元素有 2 个字母而其他元素有 1 个?
  • 到目前为止你有什么?你被困在哪里了?
  • @Rocket,他们有两个字母,因为我希望将 a 分开,在它自己的“令牌”中,这意味着 a 之前和之后的文本也进入它自己的令牌

标签: javascript arrays token tokenize


【解决方案1】:
var x = ['dcab', 'feac', 'gwad', 'dnae'];
x = x.join('-').replace(/a/g,"-a-").split('-');

更新:正如@Robert 指出的,如果您在开头或结尾有'a',这将导致'' 空白字符串出现在最终数组中。您可以通过执行以下操作来删除空白字符串来解决此问题:

x.join('-').replace(/a/g,"-a-").split('-').filter(function(x) { return x!='' });

或者,对于性能可能存在问题的较大数组,您可以使用另一个 .replace() 简单地去掉额外的分隔符(这可能是更好的方法,尽管它不那么可读):

x.join('-').replace(/a/g,"-a-").replace(/^\-|\-(?=\-)|\-$/g,'').split('-');

当然,毫无疑问,您的分隔符可以是任何东西(不一定是'-'),只要您可以保证它不会出现在您的任何字符串中。

【讨论】:

  • 我认为连接应该是'-'而不是''。
  • ...这是一个很棒的小单行字:-)
  • 我喜欢这个解决方案,又好又小。
  • 如果其中一个字符串以“a”开头或结尾或包含多个连续的“a”,则此解决方案不起作用。
  • @robert 真的,感谢您指出这一点,我没有考虑所有的情况。我已经更新了我的答案。
【解决方案2】:
var arr = ['dcab', 'feac', 'gwad', 'dnae'];
var result = [];
var i;
var s;

for (i = 0; i < arr.length; i++) {
    s = arr[i].split('a');
    result.push(s[0]);
    if (s.length > 1) {
        result.push('a');
        result.push(s[1]);
    }
}

仅当每个字符串恰好包含一个或零个“a”字符时才有效。如果它可以包含更多,您可以遍历 split 的结果。

【讨论】:

  • 非常感谢。如果您不介意,能否请您快速解释一下您的代码?我认为运行拆分会从数组中删除所有“a”
  • 如果一个字符串中有多个as怎么办?你可能需要一个内部循环。
  • 当然。 split 返回由“a”分隔的字符串部分数组。如果没有'a',它将返回一个只有一个元素的数组。无论如何,我们保留第一个元素。然后,如果找到“a”(s 有多个元素),我们将其添加到结果中,然后添加字符串的下一部分。这对给定数组的每个元素发生一次。
  • @Robert,我在代码下方提到了这一点。我不想让它变得不必要的复杂,因为给定示例中不存在这种情况。我认为处理不存在的分隔符已经超出了他的要求。
  • @bkconrad 这是有道理的。非常感谢!
【解决方案3】:
var arr = ['dcab', 'feac', 'gwad', 'dnae'];

var new_arr = arr.reduce(function(ret, val) {
    ret.push.apply(ret, val.split(/(a)/))
    return ret;
}, []);

请注意,某些旧版浏览器不支持捕获和保留拆分字符。


这样简洁一点...

var new_arr = arr.reduce(function(ret, val) {
    return ret.concat(val.split(/(a)/));
}, []);

【讨论】:

  • 谢谢@Rocket。我以为我已经在结果中看到了这个价值。
  • 我认为他想使用 'a' 作为分隔符,但 +1 因为 reduce 使用不够。
  • 谢谢!嗯,只是好奇整个 ret 和 val 是如何工作的?
  • ...也就是说,回调的第一个参数是"accumulator",第二个参数是迭代中当前项的值。 “累加器”是最后一次迭代的返回值。如果您要对数字数组中的值求和,您可以使用0 为其播种,然后使用return ret + val。每次新的迭代,ret 将是之前的返回值(当前总和),因此它会累加数组中所有项目的总和。 Here's a demo
  • 好吧,但是你不能通过首先连接所有字符串然后只调用一次 split 来使其更简洁吗?
【解决方案4】:

首先,您分别处理数组元素并提取它们的标记。然后合并结果。

您正在寻找 3 种类型的令牌:

  • 一个“a”。其正则表达式是/a/
  • 一系列其他字符 => /[^a]+/
  • 当原始元素是一个空字符串时,你想保留它 => /^$/

因此,令牌的正则表达式总共是 /a|[^a]+|^$/。要提取 所有 标记,您需要包含全局搜索标志 g

var strings = ['dcab', 'feac', 'gwad', 'dnae'];

var arrays = strings.map(function(string) {
    return string.match(/[^a]+|a|^$/g);
});

match 返回一个数组,其中包含在字符串中找到的标记。剩下要做的就是连接所有这些数组。

幸运的是,有一个数组方法仅用于此特定目的。但不幸的是,使用未知数量的数组并不容易:

var tokens = arrays[0].concat(arrays[1], arrays[2], ...

首先你不知道你有多少个数组。所以没有办法传递正确数量的参数。但也许你甚至不知道array[0] 是否存在。所以你最好使用一个空数组作为起点。

不过有办法解决这个问题。

一种解决方案是将串联分成多个步骤:

var tokens = arrays.reduce(function(result, array) {
    return result.concat(array);
}, []); // note the initial empty array

但对我来说,使用apply 并一次传递所有数组似乎更合适:

var concat = Array.prototype.concat;
var tokens = concat.apply([], arrays);

所有放在一起的代码如下所示:

var strings = ['dcab', 'feac', 'gwad', 'dnae'];
var concat = Array.prototype.concat;

var tokens = concat.apply([], strings.map(function(string) {
    return string.match(/[^a]+|a|^$/g);
}));

【讨论】: