有没有更简洁的方法来删除非字母数字字符并替换空格?

Posted

技术标签:

【中文标题】有没有更简洁的方法来删除非字母数字字符并替换空格?【英文标题】:Is there a cleaner way to remove non-alphanumeric chars and replace spaces? 【发布时间】:2013-08-22 12:57:33 【问题描述】:

我想替换所有非字母数字字符,并用下划线替换空格。到目前为止,我已经使用多个正则表达式提出了这个问题,但有没有更“有效”的方法?

"Well Done!".toLowerCase().replace(/\s/, '-').replace(/[^\w-]/gi, '');

干得好

【问题讨论】:

你不需要toLowerCase(),你的意思是破折号-而不是下划线_ 您可以使用函数作为第二个参数来决定任何给定匹配的替换内容:developer.mozilla.org/en-US/docs/Web/javascript/Reference/…。这将避免两次遍历字符串。这是否比许多短字符串的 JS 函数调用效率更高或更低是值得怀疑的。 (我的直觉告诉我“不”,但我不能胆大妄为地制作一个 jsperf。) 无论如何,您的代码有效,所以我不确定这是一个完全合适的问题。比如,什么会使答案“正确”?除了它是“不同的”,或者是第一个出现,或者你出于某种原因喜欢它。 @millimoose 似乎使用函数参数是一个不错的选择,我真正检查的是是否有一些更“智能”的正则表达式可以让我同时做这两个:) @htmlr 这是一个不同的选项。我认为在您的情况下,可读性和性能都更差。你在做两件不同的事情,做两个不同的调用就足够有意义了。 【参考方案1】:

至少在其他语言中,调用正则表达式引擎的成本很高。我不确定这是否适用于 JavaScript,但这是“C 风格”的做法。我确信自己对其性能进行基准测试将是一次宝贵的学习经验。

var x = "Well Done!";
var y = "";
var c;
for (var i = 0; i < x.length; i++)

    c = x.charCodeAt(i);
    if (c >= 48 && c <= 57 || c >= 97 && c <= 122)
    
        y += x[i];
    
    else if (c >= 65 && c <=  90)
    
        y += String.fromCharCode(c+32);
    
    else if (c == 32 || c >= 9 && c <= 13)
    
        y += '-';
    

$('#output').html(y);

有关 ASCII 代码,请参阅 http://www.asciitable.com/。这是a jsFiddle。请注意,我还实现了您的 toLowerCase(),只需将 32 添加到大写字母即可。


免责声明

当然,我个人更喜欢可读代码,因此更喜欢正则表达式,或者使用某种strtr 函数(如果存在于JavaScript 中的话)。这个答案纯粹是为了教育。

【讨论】:

鉴于 Javascript 具有 RE 字面量,它可能不会 那么 昂贵。有可能 RE 与 JS 源一起编译,而不是每次调用它。 您的功能与操作的不完全匹配。具体来说,他想要替换空格,但您只是替换空格。 \w 替换空格、制表符和换行符。 @DanielGimenez - 谢谢。我意识到了这一点,但认为转换是为了创建 slug。无论如何,我绝对应该提到它。 原来大部分被正则表达式视为空白的字符都连续放置在 ASCII 中;不确定 JavaScript 是否包含 \f\v 作为空白字符,但答案已更新为包含所有字符。【参考方案2】:

注意: 我想我可以用一个正则表达式提出一个更快的解决方案,但我做不到。下面是我失败的方法(你可以从失败中吸取教训),以及性能测试的结果,以及我的结论。

效率可以通过多种方式来衡量。如果您想减少调用的函数数量,则可以使用单个正则表达式和一个函数来处理替换。

([A-Z])|(\s)|([^a-z\d])

REY

第一组将应用toLowerCase(),第二组将替换为-,第三组将不返回任何内容。我最初对第 1 组和第 3 组使用+ 量词,但考虑到文本的预期性质,删除它会导致更快的执行。 (感谢 acheong87)

'Well Done!'.replace(/([A-Z])|(\s)|([^a-z\d])/g, function (match, $0, $1) 
    if ($0) return String.fromCharCode($0.charCodeAt(0) + 32);
    else if ($1) return '-';
    return '';
);

jsFiddle

性能

我的方法表现最差:

Acheong87  fastest
Original   16% slower
Mine       53% slower

jsPerf

结论

就代码开发时间而言,您的方法是最有效的,与 acheong87 方法相比的性能损失被代码可维护性、可读性和复杂性降低所抵消。除非速度是最重要的,否则我会使用你的版本。

我添加到正则表达式的可选匹配越多,性能损失就越大。除了功能减少之外,我想不出我的方法有什么好处,但这被if 语句和复杂性增加所抵消。

【讨论】:

不错;感谢基准测试;我不知道这个网站。我想知道如果你颠倒交替原子的顺序会有什么区别(因为空格是最稀有的,大写字母是第二稀有的,小写字母是最常见的)。此外,上述可能效率低下的原因之一是它需要回溯。我在 spirit 中看到您正在尝试最小化 replacements,但 + 强制在测试下一个交替原子之前发生“失败的匹配”,而没有+,立即更换。我不确定底层代码是什么样子的 在 JS 引擎中,但我想知道替换时间是否与字符数有关,而不是与调用次数有关。我刚刚编辑了您的测试以尝试进行这些修改;嗯,性能优势并没有我想象的那么大。确实是一个值得学习的好例子。 (现在编辑我的答案以包括正则表达式空白字符,i.e. [ \f\n\r\t\v]. @acheong87,你在这两个方面都是对的。示例文本的性质和实际用法使+ 在性能方面效率低下。如果我们预计大写字母会更频繁,更改顺序也会有所帮助。

以上是关于有没有更简洁的方法来删除非字母数字字符并替换空格?的主要内容,如果未能解决你的问题,请参考以下文章

有没有更简单的方法来过滤非字母字符? C++

python字符串如何去掉英文字母以外的字符

sed:仅删除引号内的所有非字母数字字符

用普通的ascii字符替换重音字符[重复]

Oracle 替换一些重复的字符(非数字)

python 中怎么替换字符串