如何在 JavaScript 中就地反转字符串?

IT技术 javascript string reverse
2021-01-30 09:14:49

你如何扭转就地在JavaScript字符串时,它被传递给用一个return语句的功能,而无需使用内置函数(.reverse().charAt()等等)?

6个回答

只要您处理简单的 ASCII 字符,并且您乐于使用内置函数,这将起作用:

function reverse(s){
    return s.split("").reverse().join("");
}

如果您需要支持 UTF-16 或其他多字节字符的解决方案,请注意此函数将提供无效的 unicode 字符串或看起来很有趣的有效字符串。您可能需要考虑这个答案

[...s] 是 Unicode 感知的,一个小的编辑给出:-

function reverse(s){
    return [...s].reverse().join("");
}
对于 UTF-16return [...s].reverse().join("");可能有效。
2021-03-19 09:14:49
@Richeve Bebedor“全部不使用内置函数?.reverse()”这不是一个可接受的解决方案,因为它不适合问题的范围,尽管它是在 JS 中反转字符串的可行解决方案。
2021-03-27 09:14:49
@MartinProbst 我的回答为正确处理代理对和组合标记的问题提供了一个 Unicode 感知解决方案:stackoverflow.com/a/16776380/96656
2021-04-03 09:14:49
对于包含代理项对(即基本多语言平面之外的字符)的 UTF-16 字符串,这被破坏了。对于包含组合字符的字符串,它也会给出有趣的结果,例如分音符可能出现在以下字符上。第一个问题将导致无效的 unicode 字符串,第二个问题将导致看起来很有趣的有效字符串。
2021-04-04 09:14:49
@DavidStarkey:是的,将近四年后回顾这一点,很难看出我是如何完全忽略了问题的重点。看起来我应该等两分钟,然后投票赞成 crescentfresh 对原始帖子的评论!
2021-04-05 09:14:49

以下技术(或类似技术)通常用于在 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'

至于“就地”部分,请参阅其他答案。

@Meglio 使用这种特定方法,是的。
2021-03-14 09:14:49
虽然这很好地解释了问题,但实际的答案在另一个城堡中正如@r0estir0bbe 一年多前所说,相关代码应该答案中,而不仅仅是链接。
2021-03-23 09:14:49
当然,问题是“反转字符串”听起来很明确,但它并不是面对这里提到的问题。反转字符串是否返回打印时会以相反顺序显示字符串中的字素簇的字符串?一方面,这听起来很可能。另一方面,你为什么要那样做?这个定义取决于它是否被打印,而打印一个反转的字符串很少有用。作为算法的一部分,您的要求可能完全不同。
2021-03-26 09:14:49
“希望这解释了为什么到目前为止发布的所有答案都是错误的” - 这个断言过于强烈了。许多用例不需要 UTF-16 支持(简单示例;使用 URL 和 URL 组件/参数)。解决方案不会仅仅因为它不处理非必需的场景而“错误”。值得注意的是,最高投票的答案明确声明它仅适用于 ASCII 字符,因此绝对没有一点错误。
2021-04-01 09:14:49
您应该在答案中包含 Esrever 代码的主要部分。
2021-04-06 09:14:49
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;
}
#1 是最好的,#2 可能会非常慢
2021-03-10 09:14:49
我绝对同意 String 原型。
2021-03-11 09:14:49
字符串连接很昂贵。最好构建一个数组并加入它或使用 concat()。
2021-03-23 09:14:49
但是,当存在 Unicode 复合字符时,这两种解决方案都不起作用。
2021-03-31 09:14:49
@JuanMendes 我在 2009 年留下了那条评论,过去 4 年里情况发生了变化。:P
2021-04-05 09:14:49

详细分析和十种不同的方法来反转字符串及其性能细节。

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')
如果你在小项目中,你可以这样做:String.prototype.reverse = function(){ return [...this].reverse().join("")};所以你可以得到像 'reverseme'.reverse() 这样的字符串的反转(返回值 'emesrever'),如果你想要性能优势,你可以用一个 in 替换原型函数这个答案
2021-03-14 09:14:49
为什么我们不能只做: Array.prototype.reverse.call(string) ?就像 .filter 在字符串上这样工作......
2021-04-01 09:14:49

整个“原地反转字符串”是一个陈旧的面试问题 C 程序员,被他们面试的人(也许是为了报复?),会问。不幸的是,“就地”部分不再起作用,因为几乎所有托管语言(JS、C# 等)中的字符串都使用不可变字符串,从而破坏了在不分配任何新内存的情况下移动字符串的整个想法。

虽然上面的解决方案确实确实反转了一个字符串,但它们不会在没有分配更多内存的情况下进行,因此不满足条件。您需要直接访问分配的字符串,并能够操作其原始内存位置以将其原地反转。

就我个人而言,我真的很讨厌这类面试问题,但遗憾的是,我相信我们会在未来几年继续看到它们。

也许他的意思是由垃圾收集器“管理”,至少这通常是“托管语言”或虚拟机/虚拟运行时环境的存在的意思?@虎座三郎
2021-03-20 09:14:49
至少我可以说,不久前我有一位面试官问我如何在 JS 中“就地”反转字符串时给我留下了深刻的印象,我解释了为什么这是不可能的,因为 JS 中的字符串是不可变的。我不知道这是否是他所期望的答案,还是我对他进行了一些教育。无论哪种方式都很好;)
2021-04-02 09:14:49