.reverse()
組み込み関数 (など)を使用せずに、文字列が return ステートメントで関数に渡されたときに、JavaScript でその場で文字列を反転するにはどうすればよいです.charAt()
か?
58 に答える
単純な 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 はそれを 2 つの別個のコード単位として公開します。)
しかし、もっとあります:
// 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
は実際には 2 つの記号で構成されます: 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 環境で動作します。シェルユーティリティ/バイナリが付属しているため、必要に応じて端末から文字列を簡単に逆にすることができます。
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;
}
「文字列を所定の位置に逆にする」というのは、C プログラマーの時代遅れのインタビューの質問であり、C プログラマーにインタビューされた人々は (復讐のためか?) 尋ねるでしょう。残念ながら、ほとんどすべてのマネージ言語 (JS、C# など) の文字列は不変の文字列を使用するため、機能しなくなったのは「インプレース」部分です。そのため、新しいメモリを割り当てずに文字列を移動するという考え全体が無効になります。
上記の解決策は確かに文字列を逆にしますが、より多くのメモリを割り当てずにそれを行うわけではないため、条件を満たしていません。割り当てられた文字列に直接アクセスし、元のメモリ位置を操作して元の位置に戻すことができる必要があります。
個人的には、この種のインタビューの質問は本当に嫌いですが、悲しいことに、今後何年もこのような質問を目にすることになるでしょう。
最初にArray.from()
、文字列を配列に変換するために使用し、次にArray.prototype.reverse()
配列を逆にし、次にArray.prototype.join()
文字列に戻します。
const reverse = str => Array.from(str).reverse().join('');
ECMAScript 6 では、次のようにスプレッド演算子.split('')
を使用して、split メソッドを使用せずに文字列をさらに高速に反転できます。
var str = [...'racecar'].reverse().join('');
私はパーティーに3年遅れているようです...
残念ながら、指摘されているようにできません。JavaScript 文字列は不変ですか?を参照してください。JavaScript で「文字列ビルダー」が必要ですか?
あなたができる次善の策は、「ビュー」または「ラッパー」を作成することです。これは、文字列を取り、使用している文字列 API のあらゆる部分を再実装しますが、文字列が逆になっているふりをします。例えば:
var identity = function(x){return x};
function LazyString(s) {
this.original = s;
this.length = s.length;
this.start = 0; this.stop = this.length; this.dir = 1; // "virtual" slicing
// (dir=-1 if reversed)
this._caseTransform = identity;
}
// syntactic sugar to create new object:
function S(s) {
return new LazyString(s);
}
//We now implement a `"...".reversed` which toggles a flag which will change our math:
(function(){ // begin anonymous scope
var x = LazyString.prototype;
// Addition to the String API
x.reversed = function() {
var s = new LazyString(this.original);
s.start = this.stop - this.dir;
s.stop = this.start - this.dir;
s.dir = -1*this.dir;
s.length = this.length;
s._caseTransform = this._caseTransform;
return s;
}
//We also override string coercion for some extra versatility (not really necessary):
// OVERRIDE STRING COERCION
// - for string concatenation e.g. "abc"+reversed("abc")
x.toString = function() {
if (typeof this._realized == 'undefined') { // cached, to avoid recalculation
this._realized = this.dir==1 ?
this.original.slice(this.start,this.stop) :
this.original.slice(this.stop+1,this.start+1).split("").reverse().join("");
this._realized = this._caseTransform.call(this._realized, this._realized);
}
return this._realized;
}
//Now we reimplement the String API by doing some math:
// String API:
// Do some math to figure out which character we really want
x.charAt = function(i) {
return this.slice(i, i+1).toString();
}
x.charCodeAt = function(i) {
return this.slice(i, i+1).toString().charCodeAt(0);
}
// Slicing functions:
x.slice = function(start,stop) {
// lazy chaining version of https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice
if (stop===undefined)
stop = this.length;
var relativeStart = start<0 ? this.length+start : start;
var relativeStop = stop<0 ? this.length+stop : stop;
if (relativeStart >= this.length)
relativeStart = this.length;
if (relativeStart < 0)
relativeStart = 0;
if (relativeStop > this.length)
relativeStop = this.length;
if (relativeStop < 0)
relativeStop = 0;
if (relativeStop < relativeStart)
relativeStop = relativeStart;
var s = new LazyString(this.original);
s.length = relativeStop - relativeStart;
s.start = this.start + this.dir*relativeStart;
s.stop = s.start + this.dir*s.length;
s.dir = this.dir;
//console.log([this.start,this.stop,this.dir,this.length], [s.start,s.stop,s.dir,s.length])
s._caseTransform = this._caseTransform;
return s;
}
x.substring = function() {
// ...
}
x.substr = function() {
// ...
}
//Miscellaneous functions:
// Iterative search
x.indexOf = function(value) {
for(var i=0; i<this.length; i++)
if (value==this.charAt(i))
return i;
return -1;
}
x.lastIndexOf = function() {
for(var i=this.length-1; i>=0; i--)
if (value==this.charAt(i))
return i;
return -1;
}
// The following functions are too complicated to reimplement easily.
// Instead just realize the slice and do it the usual non-in-place way.
x.match = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.replace = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.search = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.split = function() {
var s = this.toString();
return s.apply(s, arguments);
}
// Case transforms:
x.toLowerCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toLowerCase;
s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;
return s;
}
x.toUpperCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toUpperCase;
s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;
return s;
}
})() // end anonymous scope
デモ:
> r = S('abcABC')
LazyString
original: "abcABC"
__proto__: LazyString
> r.charAt(1); // doesn't reverse string!!! (good if very long)
"B"
> r.toLowerCase() // must reverse string, so does so
"cbacba"
> r.toUpperCase() // string already reversed: no extra work
"CBACBA"
> r + '-demo-' + r // natural coercion, string already reversed: no extra work
"CBAcba-demo-CBAcba"
キッカー -- 以下は、純粋な数学によってインプレースで実行され、各文字を 1 回だけ、必要な場合にのみアクセスします。
> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"
> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"
これを非常に大きな文字列に適用すると、その比較的小さなスライスのみを取得する場合に、大幅な節約が得られます。
これが価値があるかどうか (ほとんどのプログラミング言語のようにコピーとして反転するより) は、ユース ケースと文字列 API をどれだけ効率的に再実装するかに大きく依存します。たとえば、必要なのが文字列インデックス操作を行うこと、または小さなslice
s またはsubstr
s を取得することだけである場合、これによりスペースと時間が節約されます。ただし、大きな反転スライスまたは部分文字列を印刷することを計画している場合、完全なコピーを実行した場合よりもさらに悪い節約になる可能性があります。「逆」文字列にも typestring
はありませんが、プロトタイピングでこれを偽造できる場合があります。
上記のデモの実装では、ReversedString 型の新しいオブジェクトを作成します。これはプロトタイプ化されているため、かなり効率的であり、最小限の作業と最小限のスペース オーバーヘッドで済みます (プロトタイプ定義は共有されます)。これは遅延スライスを含む遅延実装です。.slice
またはのような関数を実行するたびに.reversed
、指数計算が実行されます。最後に、(暗黙的に.toString()
or.charCodeAt(...)
または something を呼び出すことによって) データを抽出すると、「スマート」な方法でそれらが適用され、可能な限り最小限のデータに触れます。
注: 上記の文字列 API は一例であり、完全に実装されていない場合があります。また、必要な機能を 1 ~ 2 つだけ使用することもできます。
スプレッド構文を使用した読みやすい方法:
const reverseString = str => [...str].reverse().join('');
console.log(reverseString('ABC'));
var str = 'sample string';
[].map.call(str, function(x) {
return x;
}).reverse().join('');
また
var str = 'sample string';
console.log(str.split('').reverse().join(''));
// 出力: 'gnirts elpmas'
これが私が考える最も簡単な方法です
var reverse = function(str) {
var arr = [];
for (var i = 0, len = str.length; i <= len; i++) {
arr.push(str.charAt(len - i))
}
return arr.join('');
}
console.log(reverse('I want a '));
組み込み関数を使用したくない場合。これを試して
var string = 'abcdefg';
var newstring = '';
for(let i = 0; i < string.length; i++){
newstring = string[i] += newstring;
}
console.log(newstring);
これはよく答えられた古い質問であることは知っていますが、私自身の娯楽のために、次の逆関数を書き、他の人に役立つ場合に備えて共有すると思いました。サロゲート ペアと結合マークの両方を処理します。
function StringReverse (str)
{
var charArray = [];
for (var i = 0; i < str.length; i++)
{
if (i+1 < str.length)
{
var value = str.charCodeAt(i);
var nextValue = str.charCodeAt(i+1);
if ( ( value >= 0xD800 && value <= 0xDBFF
&& (nextValue & 0xFC00) == 0xDC00) // Surrogate pair)
|| (nextValue >= 0x0300 && nextValue <= 0x036F)) // Combining marks
{
charArray.unshift(str.substring(i, i+2));
i++; // Skip the other half
continue;
}
}
// Otherwise we just have a rogue surrogate marker or a plain old character.
charArray.unshift(str[i]);
}
return charArray.join('');
}
Mathias、Punycode、および JavaScript での文字エンコーディングの複雑さについて私を教育するためのその他のさまざまなリファレンスのすべての小道具。
String.prototype.reverse はこの問題を解決する良い方法だと思います。以下のコード;
String.prototype.reverse = function() {
return this.split('').reverse().join('');
}
var str = 'this is a good example for string reverse';
str.reverse();
-> "esrever gnirts rof elpmaxe doog a si siht";
本当の答えは、その場で逆にすることはできませんが、逆の新しい文字列を作成することはできます。
再帰をいじる練習として: インタビューに行くと、インタビュアーが再帰を使ってこれを行う方法を尋ねることがあります。スタックオーバーフローを簡単に引き起こす可能性があります" O(n)
( O(log n)
.O(log n)
しかし、そうであればO(n)
、簡単にスタック オーバーフローが発生する可能性があります。
時々インタビュアーはあなたに「練習として、再帰を使って書いてみませんか?」と尋ねます。そして、ここにあります:
String.prototype.reverse = function() {
if (this.length <= 1) return this;
else return this.slice(1).reverse() + this.slice(0,1);
}
テスト走行:
var s = "";
for(var i = 0; i < 1000; i++) {
s += ("apple" + i);
}
console.log(s.reverse());
出力:
999elppa899elppa...2elppa1elppa0elppa
スタック オーバーフローを取得するために、Google Chromeに変更1000
したところ、次のように報告されました。10000
RangeError: Maximum call stack size exceeded
var str = "my name is saurabh ";
var empStr='',finalString='';
var chunk=[];
function reverse(str){
var i,j=0,n=str.length;
for(i=0;i<n;++i){
if(str[i]===' '){
chunk[j]=empStr;
empStr = '';
j++;
}else{
empStr=empStr+str[i];
}
}
for(var z=chunk.length-1;z>=0;z--){
finalString = finalString +' '+ chunk[z];
console.log(finalString);
}
return true;
}
reverse(str);
私自身のオリジナルの試み...
var str = "The Car";
function reverseStr(str) {
var reversed = "";
var len = str.length;
for (var i = 1; i < (len + 1); i++) {
reversed += str[len - i];
}
return reversed;
}
var strReverse = reverseStr(str);
console.log(strReverse);
// "raC ehT"
Array.prototype.reverse を使用しない基本的な ES6 不変の例を次に示します。
// :: reverse = String -> String
const reverse = s => [].reduceRight.call(s, (a, b) => a + b)
console.log(reverse('foo')) // => 'oof'
console.log(reverse('bar')) // => 'rab'
console.log(reverse('foo-bar')) // => 'rab-oof'
JavaScript で文字列を逆にする最良の方法
1) Array.reverse:
おそらく、文字列を反転していると思っていたのに、なぜ Array.reverse メソッドを使用しているのかと考えているでしょう。String.split メソッドを使用して、文字列を文字の配列に変換しています。次に、配列内の各値の順序を逆にし、最後に Array.join メソッドを使用して配列を文字列に戻します。
function reverseString(str) {
return str.split('').reverse().join('');
}
reverseString('dwayne');
2) while ループのデクリメント:
かなり冗長ですが、このソリューションにはソリューション 1 よりも優れた利点があります。配列を作成しているのではなく、ソース文字列の文字に基づいて文字列を連結しているだけです。
パフォーマンスの観点からは、おそらくこれが最良の結果をもたらすでしょう (ただし、テストされていません)。ただし、非常に長い文字列の場合、パフォーマンスの向上が窓の外に落ちる可能性があります。
function reverseString(str) {
var temp = '';
var i = str.length;
while (i > 0) {
temp += str.substring(i - 1, i);
i--;
}
return temp;
}
reverseString('dwayne');
3) 再帰
このソリューションがいかにシンプルで明確かが気に入っています。String.charAt メソッドと String.substr メソッドを使用して、文字列が空になるまで毎回自分自身を呼び出すことにより、異なる値を渡すために使用されていることがはっきりとわかります。再帰を使用して自分自身を呼び出すのではなく、3 進数が空の文字列を返すだけです。 . これにより、おそらく 2 番目のソリューションに次いで 2 番目に優れたパフォーマンスが得られます。
function reverseString(str) {
return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
ES6
function reverseString(str) {
return [...str].reverse().join("");
}
console.log(reverseString("Hello")); // olleH
function reverseString(string) {
var reversedString = "";
var stringLength = string.length - 1;
for (var i = stringLength; i >= 0; i--) {
reversedString += string[i];
}
return reversedString;
}
別のバリエーション(IEで動作しますか?):
String.prototype.reverse = function() {
for (i=1,s=""; i<=this.length; s+=this.substr(-i++,1)) {}
return s;
}
編集:
これには、組み込み関数を使用しません。
String.prototype.reverse = function() {
for (i=this[-1],s=""; i>=0; s+=this[i--]) {}
return s;
}
注:this[-1]は文字列の長さを保持します。
ただし、個々の配列要素への割り当てはStringオブジェクト(保護されていますか?)では機能しないため、文字列を元の場所に戻すことはできません。つまり、割り当てを行うことはできますが、結果の文字列は変更されません。
var str = "IAMA JavaScript Developer";
var a=str.split(''), b = a.length;
for (var i=0; i<b; i++) {
a.unshift(a.splice(1+i,1).shift())
}
a.shift();
alert(a.join(''));
このようなことを試すことができます。リファクタリングの余地があると確信しています。分割機能を使用して回避できませんでした。誰かが分割せずにそれを行う方法を知っているかもしれません。
設定するコード。これを .js ライブラリに入れることができます
それを使用するコード (ブラウザでテストされているため、クライアント側のコードがあります):
var sentence = "My Stack is Overflowing."
document.write(sentence.reverseLetters() + '<br />');
document.write(sentence.reverseWords() + '<br />');
スニペット:
String.prototype.aggregate = function(vals, aggregateFunction) {
var temp = '';
for (var i = vals.length - 1; i >= 0; i--) {
temp = aggregateFunction(vals[i], temp);
}
return temp;
}
String.prototype.reverseLetters = function() {
return this.aggregate(this.split(''),
function(current, word) {
return word + current;
})
}
String.prototype.reverseWords = function() {
return this.aggregate(this.split(' '),
function(current, word) {
return word + ' ' + current;
})
}
var sentence = "My Stack is Overflowing."
document.write(sentence.reverseLetters() + '<br />');
document.write(sentence.reverseWords() + '<br />');
以下は、文字列を再帰的に逆にしようとしている人に役立つかもしれません。最近の就職面接で、関数型プログラミング スタイルを使用してこれを行うように求められました。
var reverseStr = function(str) {
return (str.length > 0) ? str[str.length - 1] + reverseStr(str.substr(0, str.length - 1)) : '';
};
//tests
console.log(reverseStr('setab retsam')); //master bates
function reverse(str){
var s = "";
for (var i = str.length - 1; i >= 0; i--){
s += str[i];
}
return s;
};
reverse("your string comes here")
String プロトタイプに追加することは理想的ですが (コア JS 言語に追加される場合に備えて)、最初に存在するかどうかを確認し、存在しない場合は追加する必要があります。次のようにします。
String.prototype.reverse = String.prototype.reverse || function () {
return this.split('').reverse().join('');
};
function reverse_string(string)
{
var string;
var len = string.length;
var stringExp = string.split('');
var i;
for (i = len-1; i >=0;i--)
{
var result = document.write(stringExp[i]);
}
return result;
}
reverse_string("This is a reversed string");
//出力: gnirts desrever a si sihT
function reverseWords(str) {
// Go for it
const invertirPalabra = palabra => palabra.split('').reverse().join('')
return str.split(' ').map(invertirPalabra).join(' ')
// con split convierto string en array de palabras, le paso ' '
// que es que me lo separe por espacios
// luego invierto cada palabra...
// y luego con join las uno separando por espacios
}
//recursive implementation
function reverse(wrd) {
const str =wrd[0]
if(!wrd.length) {
return wrd
}
return reverse(wrd.slice(1)) + str
}