Javascript 拆分数组

Posted

技术标签:

【中文标题】Javascript 拆分数组【英文标题】:Javascript Split Array 【发布时间】:2011-10-09 17:49:50 【问题描述】:

我正在尝试编写一个自定义字符串拆分函数,它比我预期的要难。

基本上,我传入一个字符串和一个字符串将拆分的值的数组,它将返回一个子字符串数组,删除空的并包括它拆分的值。如果字符串可以在同一位置被两个不同的值分割,则较长的优先。

也就是说,

split("Go ye away, I want some peace && quiet. & Thanks.", ["Go ", ",", "&&", "&", "."]);

应该返回

["Go ", "ye away", ",", " I want some peace ", "&&", " quiet", ".", " ", "&", " Thanks", "."]

你能想出一个相当简单的算法吗?如果在 javascript 中有内置的方法可以做到这一点(我认为没有),那就更好了。

【问题讨论】:

应该将"ye ""away" 分开吗?如果我理解的话,似乎应该只是一个。 您的意思是将“”作为您的分隔符之一吗?您的输出似乎表明了这一点,但您的输入却没有。 @kingjiv 是的,这是一个错误。现在应该修好了。 @Raul 否。如果输出在两个分隔符之间,则只有一个字符串。您会注意到" I want some peace " 不会按空格分割。 这个用例可能是什么? 【参考方案1】:

类似this?

function mySplit(input, delimiters) 

    // Sort delimiters array by length to avoid ambiguity
    delimiters.sort(function(a, b) 
       if (a.length > b.length)  return -1; 
       return 0;
    

    var result = [];

    // Examine input one character at a time
    for (var i = 0; i < input.length; i++) 
        for (var j = 0; j < delimiters.length; j++) 
            if (input.substr(i, delimiters[j].length) == delimiters[j]) 

                // Add first chunk of input to result
                if (i > 0) 
                    result.push(input.substr(0, i));
                
                result.push(delimiters[j]);

                // Reset input and iteration
                input = input.substr(i + delimiters[j].length);
                i = 0;
                j = 0;
            
        
    

    return result;


var input      = "Go ye away, I want some peace && quiet. & Thanks.";
var delimiters = ["Go ", ",", "&&", "&", "."];

console.log(mySplit(input, delimiters));
// Output: ["Go ", "ye away", ",", " I want some peace ",
//          "&&", " quiet", ".", " ", "&", " Thanks", "."]

【讨论】:

它有效,酷!我感到很尴尬......这是我自己的解决方案大小的三分之一,但无法正常工作。 在发生冲突的情况下,这不会优先考虑更长的分隔符(我认为是问题中的一个要求)。如果你在分隔符数组中切换“&&”和“&”,它会在“&”而不是“&&”上分割 确实如此。它具有从左到右的优先级。如果 OP 需要不同的语义,他可以按长度对分隔符列表进行排序。但这在问题中没有说明,并且给定的分隔符列表中没有歧义。 [编辑:哦,它在问题中说明的!我将添加排序。谢谢@Bob!]【参考方案2】:

要求的确切解决方案:

function megasplit(toSplit, splitters) 
    var splitters = splitters.sorted(function(a,b) return b.length-a.length);
                                                          // sort by length; put here for readability, trivial to separate rest of function into helper function
    if (!splitters.length)
        return toSplit;
    else 
        var token = splitters[0];
        return toSplit
            .split(token)             // split on token
            .map(function(segment)   // recurse on segments
                 return megasplit(segment, splitters.slice(1))
             )
            .intersperse(token)       // re-insert token
            .flatten()                // rejoin segments
            .filter(Boolean);
    

演示:

> megasplit(
      "Go ye away, I want some peace && quiet. & Thanks.",
      ["Go ", ",", "&&", "&", "."]
  )
["Go ", "ye away", ",", " I want some peace ", "&", "&", " quiet", ".", " ", "&", " Thanks", "."]

机械(可重复使用!):

Array.prototype.copy = function() 
    return this.slice()

Array.prototype.sorted = function() 
    var copy = this.copy();
    copy.sort.apply(copy, arguments);
    return copy;

Array.prototype.flatten = function() 
    return [].concat.apply([], this)

Array.prototype.mapFlatten = function() 
    return this.map.apply(this,arguments).flatten()

Array.prototype.intersperse = function(token) 
    // [1,2,3].intersperse('x') -> [1,'x',2,'x',3]
    return this.mapFlatten(function(x)return [token,x]).slice(1)


注意事项:

这需要大量的研究才能优雅地完成: (Deep) copying an array using jQuery What is the most efficient way to concatenate N arrays in JavaScript?(创建了我自己的不那么难看的方法) How can I split text on commas not within double quotes, while keeping the quotes?(垃圾答案,再次创建了我自己的方法) 由于规范要求令牌(尽管它们将留在字符串中)不应该被拆分(否则你会得到"&amp;", "&amp;"),这使情况变得更加复杂。这使得使用reduce 成为不可能和必要的递归。 我个人也不会忽略带有拆分的空字符串。我可以理解不想在令牌上递归拆分,但我个人会简化函数并使输出表现得像普通的 .split["", "Go ", "ye away", ",", " I want some peace ", "&amp;&amp;", " quiet", ".", " ", "&amp;", " Thanks", ".", ""] 我应该指出,如果您愿意稍微放宽您的要求,这将从 15/20-liner 变为 1/3-liner

1-liner,如果遵循规范拆分行为:

Array.prototype.mapFlatten = function() 
    ...

function megasplit(toSplit, splitters) 
    return splitters.sorted(...).reduce(function(strings, token) 
        return strings.mapFlatten(function(s)return s.split(token));
    , [toSplit]);

3-liner,如果上面的内容难以阅读:

Array.prototype.mapFlatten = function() 
    ...

function megasplit(toSplit, splitters) 
    var strings = [toSplit];
    splitters.sorted(...).forEach(function(token) 
        strings = strings.mapFlatten(function(s)return s.split(token));
    );
    return strings;

【讨论】:

“要求的确切解决方案”如何?您的输出不匹配。

以上是关于Javascript 拆分数组的主要内容,如果未能解决你的问题,请参考以下文章

将数组拆分为多个数组或备用 - Javascript

如何拆分 JavaScript 多维数组并获取最后一个数组?

如何将字符串拆分为javascript数组? [复制]

javascript 将数组拆分为相同大小的块

如何在javascript中将大数组拆分为小数组? [复制]

如何在JavaScript中将数组数组拆分为单个数字?