带有特殊字符破折号 (-) 和下划线 (_) 的 Javascript 自定义排序

Posted

技术标签:

【中文标题】带有特殊字符破折号 (-) 和下划线 (_) 的 Javascript 自定义排序【英文标题】:Javascript custom sort with special characters dash (-) and underscore (_) 【发布时间】:2019-05-15 07:16:26 【问题描述】:

我正在尝试按照以下顺序进行自定义排序

    特殊字符(- 第一个,_ 最后一个) 数字 字母表

例如,如果我在下面排序

var words = ['MBC-PEP-1', 'MBC-PEP01', 'MBC-PEP91', 'MBC-PEPA1', 'MBC-PEPZ1', 'MBC-PEP_1'];

结果应该是

MBC-PEP-1,MBC-PEP_1,MBC-PEP01,MBC-PEP91,MBC-PEPA1,MBC-PEPZ1

通过使用我的代码,结果如下

"MBC-PEP-1", "MBC-PEP01", "MBC-PEP91", "MBC-PEP_1", "MBC-PEPA1", "MBC-PEPZ1"

但是我需要上面的排序顺序,不知道怎么实现。

function MySort(alphabet)

    return function(a, b) 
        var lowerA = a.toLowerCase()
        var lowerB = b.toLowerCase()
        var index_a = alphabet.indexOf(lowerA[0]),
        index_b = alphabet.indexOf(lowerB[0]);

        if (index_a === index_b) 
            // same first character, sort regular
            if (a < b) 
                return -1;
             else if (a > b) 
                return 1;
            
            return 0;
         else 
            return index_a - index_b;
        
    


var items = ['MBC-PEP-1', 'MBC-PEP01', 'MBC-PEP91', 'MBC-PEPA1', 'MBC-PEPZ1', 'MBC-PEP_1'],
sorter = MySort('-_0123456789abcdefghijklmnopqrstuvwxyz');

console.log(items.sort(sorter));

【问题讨论】:

【参考方案1】:

我将答案从 here 移植到 javascript,它可以在不使用递归或任何过于复杂的情况下完成您想要的操作:

function MySort(alphabet) 
    return function (a, b) 
       a = a.toLowerCase();
       b = b.toLowerCase();
       var pos1 = 0;
       var pos2 = 0;
       for (var i = 0; i < Math.min(a.length, b.length) && pos1 == pos2; i++) 
          pos1 = alphabet.indexOf(a[i]);
          pos2 = alphabet.indexOf(b[i]);
       

       if (pos1 == pos2 && a.length != b.length) 
           return o1.length - o2.length;
       

       return pos1 - pos2;
    ;

    
var items = ['MBC-PEP-1', 'MBC-PEP01', 'MBC-PEP91', 'MBC-PEPA1', 'MBC-PEPZ1', 'MBC-PEP_1'],
sorter = MySort('-_0123456789abcdefghijklmnopqrstuvwxyz');

console.log(items.sort(sorter));

【讨论】:

【参考方案2】:

正如 Narigo 在他们的回答中所说,您只是在比较第一个字符。这是一个可能更简单的不同想法:

function MySort(a, b) 
  a = a.replace("_", ".");
  b = b.replace("_", ".");
  return a.localeCompare(b);


var items = ['MBC-PEP-1', 'MBC-PEP01', 'MBC-PEP91', 'MBC-PEPA1', 'MBC-PEPZ1', 'MBC-PEP_1'];

console.log(items.sort(MySort));

我们基本上使用普通的字符串比较,除了我们将下划线更改为点来决定排序,因为它与您想要实现的目标兼容。

【讨论】:

我不推荐这个答案,因为当输入突然开始包含. 并且需要以不同的顺序指定时会发生什么?对此进行维护很困难,因为您无法实际定义所需的顺序。 @Cᴏʀʏ 如果希望字符串格式更通用,那么应该在问题中说明;)我认为这是给定信息的最佳答案。 我在这里必须同意 Cᴏʀʏ。对我来说,能够使用本机功能是一种创造性的技巧,但它听起来并不像一个可维护的解决方案。 绝对有一些优点。虽然我不认为在字符串中有一个点会是一个问题,但它会正常排序。发布的其他解决方案也这样做或完全忽略这种情况。 @Aioros 我不同意他们关于这是“黑客”的观点,但我确实对 this benchmark 表示赞赏,这表明您的解决方案是最慢的。这实际上是由于localeCompare() 的内部复杂性而不是您的方法。我建议使用return -(a &lt; b) || +(a &gt; b);,我解释了in this answer,并且正如基准所展示的那样,将所有这些答案从水中吹走。【参考方案3】:

您只查看算法中的第一个字符。您还需要检查更多的字符串/下一个字符。这是一个使用递归的快速解决方案:

function MySort(alphabet)

    return function recSorter(a, b) 
        var lowerA = a.toLowerCase()
        var lowerB = b.toLowerCase()
        var index_a = alphabet.indexOf(lowerA[0]),
        index_b = alphabet.indexOf(lowerB[0]);

        if (index_a === index_b && index_a >= 0) 
            return recSorter(a.slice(1), b.slice(1));
         else 
            return index_a - index_b;
        
    


var items = ['MBC-PEP-1', 'MBC-PEP01', 'MBC-PEP91', 'MBC-PEPA1', 'MBC-PEPZ1', 'MBC-PEP_1'],
sorter = MySort('-_0123456789abcdefghijklmnopqrstuvwxyz');

console.log(items.sort(sorter));

当您有不同长度的字符串、字母表之外的字符或其他边缘情况时,我不确定您想要发生什么。对于发布的示例,这会产生预期的顺序。

【讨论】:

一种递归的、范围内的排序方法?这对于一个简单的字符串比较算法来说似乎相当昂贵...... 我不建议将此作为绩效奖。如果您想按自己的字母排序,例如按键盘上的出现排序(qwertyuiopasdfghjklzxcvbnm 而不是a-z),您仍然需要映射到自己的索引并进行比较。您可能会更快地编写命令式循环,但由于这是尾递归、可读并且可能比替换源字符串中的字符更少,所以我会保留这个答案... ;) 如果您可以参考实际上具有尾调用递归优化的 JavaScript 实现,我会印象深刻,所以我不确定为什么指出它的尾递归是相关的。我也不会完全称其为可读或“更少的黑客”。 ASCII 排序是众所周知的,因此只要用简短的注释记录意图,就可以通过简单的字符串替换来利用它。 对我来说,尾递归通常更容易让我头疼。问题是,替换一个字符串然后比较替换的字符串对我来说听起来不是一个好策略。如果您想从中获得最大的性能,请使用 Cᴏʀʏ 的解决方案 同意不同意。将字符串比较委托给实现几乎总是比在用户空间中显式迭代字符串要快。 Cᴏʀʏ 的答案还使用toLowerCase() 操作初始字符串,因此尝试使用原始字符串甚至没有节省时间。

以上是关于带有特殊字符破折号 (-) 和下划线 (_) 的 Javascript 自定义排序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有编解码器值的 python .replace 来删除特殊字符?

生成 SEO 友好的 URL(slug)[关闭]

Apache - 将下划线转换为标题中的破折号

如何验证字符串是不是仅包含字母、数字、下划线和破折号?

URL:破折号与下划线 [关闭]

如何在qt标签中显示em破折号字符?