你如何扭转就地在JavaScript字符串时,它被传递给用一个return语句的功能,而无需使用内置函数(.reverse()
,.charAt()
等等)?
如何在 JavaScript 中就地反转字符串?
只要您处理简单的 ASCII 字符,并且您乐于使用内置函数,这将起作用:
function reverse(s){
return s.split("").reverse().join("");
}
如果您需要支持 UTF-16 或其他多字节字符的解决方案,请注意此函数将提供无效的 unicode 字符串或看起来很有趣的有效字符串。您可能需要考虑这个答案。
[...s] 是 Unicode 感知的,一个小的编辑给出:-
function reverse(s){
return [...s].reverse().join("");
}
以下技术(或类似技术)通常用于在 JavaScript 中反转字符串:
// Don’t use this!
var naiveReverse = function(string) {
return string.split('').reverse().join('');
}
事实上,到目前为止发布的所有答案都是这种模式的变体。但是,此解决方案存在一些问题。例如:
naiveReverse('foo 𝌆 bar');
// → 'rab �� oof'
// Where did the `𝌆` symbol go? Whoops!
如果您想知道为什么会发生这种情况,请阅读 JavaScript 的内部字符编码。(TL;DR:𝌆
是一个星体符号,JavaScript 将它公开为两个独立的代码单元。)
但还有更多:
// To see which symbols are being used here, check:
// http://mothereff.in/js-escapes#1ma%C3%B1ana%20man%CC%83ana
naiveReverse('mañana mañana');
// → 'anãnam anañam'
// Wait, so now the tilde is applied to the `a` instead of the `n`? WAT.
测试字符串反向实现的好字符串如下:
'foo 𝌆 bar mañana mañana'
为什么?因为它包含一个星形符号 ( 𝌆
)(在 JavaScript 中由代理对表示)和一个组合标记(ñ
最后一个mañana
实际上由两个符号组成:U+006E LATIN SMALL LETTER N 和 U+0303 COMBINING TILDE)。
代理对出现的顺序不能颠倒,否则星体符号将不再出现在“颠倒”字符串中。这就是您��
在上一个示例的输出中看到这些标记的原因。
组合标记始终应用于前一个符号,因此您必须将主符号(U+006E LATIN SMALL LETTER N)视为组合标记(U+0303 COMBINING TILDE)作为一个整体。颠倒它们的顺序将导致组合标记与字符串中的另一个符号配对。这就是为什么示例输出有ã
而不是ñ
.
希望这可以解释为什么到目前为止发布的所有答案都是错误的。
为了回答您最初的问题——如何[正确地] 在 JavaScript 中反转字符串——,我编写了一个能够识别 Unicode 字符串反转的小型 JavaScript 库。它没有我刚才提到的任何问题。该库名为Esrever;它的代码在 GitHub 上,几乎可以在任何 JavaScript 环境中使用。它带有一个 shell 实用程序/二进制文件,因此您可以根据需要轻松地从终端反转字符串。
var input = 'foo 𝌆 bar mañana mañana';
esrever.reverse(input);
// → 'anañam anañam rab 𝌆 oof'
至于“就地”部分,请参阅其他答案。
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}
或者
String.prototype.reverse_string = function() {
var s = "";
var i = this.length;
while (i>0) {
s += this.substring(i-1,i);
i--;
}
return s;
}
详细分析和十种不同的方法来反转字符串及其性能细节。
http://eddmann.com/posts/ten-ways-to-reverse-a-string-in-javascript/
这些实现的性能:
每个浏览器的最佳性能实现
- Chrome 15 - 实现 1 和 6
- Firefox 7 - 实现 6
- IE 9 - 实现 4
- Opera 12 - 实现 9
以下是这些实现:
实施1:
function reverse(s) {
var o = '';
for (var i = s.length - 1; i >= 0; i--)
o += s[i];
return o;
}
实施2:
function reverse(s) {
var o = [];
for (var i = s.length - 1, j = 0; i >= 0; i--, j++)
o[j] = s[i];
return o.join('');
}
实施3:
function reverse(s) {
var o = [];
for (var i = 0, len = s.length; i <= len; i++)
o.push(s.charAt(len - i));
return o.join('');
}
实施4:
function reverse(s) {
return s.split('').reverse().join('');
}
实施5:
function reverse(s) {
var i = s.length,
o = '';
while (i > 0) {
o += s.substring(i - 1, i);
i--;
}
return o;
}
实施6:
function reverse(s) {
for (var i = s.length - 1, o = ''; i >= 0; o += s[i--]) { }
return o;
}
实施7:
function reverse(s) {
return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}
实施8:
function reverse(s) {
function rev(s, len, o) {
return (len === 0) ? o : rev(s, --len, (o += s[len]));
};
return rev(s, s.length, '');
}
实施9:
function reverse(s) {
s = s.split('');
var len = s.length,
halfIndex = Math.floor(len / 2) - 1,
tmp;
for (var i = 0; i <= halfIndex; i++) {
tmp = s[len - i - 1];
s[len - i - 1] = s[i];
s[i] = tmp;
}
return s.join('');
}
实施10
function reverse(s) {
if (s.length < 2)
return s;
var halfIndex = Math.ceil(s.length / 2);
return reverse(s.substr(halfIndex)) +
reverse(s.substr(0, halfIndex));
}
实施 11
var reverser = function(str){
let string = str.split('');
for(i=0;i<string.length;i++){
debugger;
string.splice(i,0,string.pop());
}
console.log(string.join())
}
reverser('abcdef')
整个“原地反转字符串”是一个陈旧的面试问题 C 程序员,被他们面试的人(也许是为了报复?),会问。不幸的是,“就地”部分不再起作用,因为几乎所有托管语言(JS、C# 等)中的字符串都使用不可变字符串,从而破坏了在不分配任何新内存的情况下移动字符串的整个想法。
虽然上面的解决方案确实确实反转了一个字符串,但它们不会在没有分配更多内存的情况下进行,因此不满足条件。您需要直接访问分配的字符串,并能够操作其原始内存位置以将其原地反转。
就我个人而言,我真的很讨厌这类面试问题,但遗憾的是,我相信我们会在未来几年继续看到它们。