Làm thế nào để bạn đảo ngược một chuỗi tại chỗ (hoặc tại chỗ) trong JavaScript khi nó được chuyển đến một hàm bằng câu lệnh return, mà không sử dụng các hàm dựng sẵn ( .reverse()
, .charAt()
v.v.)?
Làm thế nào để bạn đảo ngược một chuỗi tại chỗ (hoặc tại chỗ) trong JavaScript khi nó được chuyển đến một hàm bằng câu lệnh return, mà không sử dụng các hàm dựng sẵn ( .reverse()
, .charAt()
v.v.)?
Câu trả lời:
Miễn là bạn đang xử lý các ký tự ASCII đơn giản và bạn vui lòng sử dụng các hàm tích hợp, điều này sẽ hoạt động:
function reverse(s){
return s.split("").reverse().join("");
}
Nếu bạn cần một giải pháp hỗ trợ UTF-16 hoặc các ký tự nhiều byte khác, hãy lưu ý rằng hàm này sẽ cung cấp các chuỗi unicode không hợp lệ hoặc các chuỗi hợp lệ trông buồn cười. Bạn có thể muốn xem xét câu trả lời này thay thế .
[... s] là nhận biết Unicode, một chỉnh sửa nhỏ mang lại: -
function reverse(s){
return [...s].reverse().join("");
}
return [...s].reverse().join("");
có thể hoạt động.
Kỹ thuật sau (hoặc tương tự) thường được sử dụng để đảo ngược chuỗi trong JavaScript:
// Don’t use this!
var naiveReverse = function(string) {
return string.split('').reverse().join('');
}
Trong thực tế, tất cả các câu trả lời được đăng cho đến nay là một biến thể của mẫu này. Tuy nhiên, có một số vấn đề với giải pháp này. Ví dụ:
naiveReverse('foo 𝌆 bar');
// → 'rab �� oof'
// Where did the `𝌆` symbol go? Whoops!
Nếu bạn đang tự hỏi tại sao điều này xảy ra, hãy đọc mã hóa ký tự bên trong của JavaScript . (TL; DR: 𝌆
là một biểu tượng vĩ đại và JavaScript hiển thị nó dưới dạng hai đơn vị mã riêng biệt.)
Nhưng còn nữa:
// 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.
Một chuỗi tốt để kiểm tra việc triển khai ngược chuỗi là như sau :
'foo 𝌆 bar mañana mañana'
Tại sao? Bởi vì nó chứa một biểu tượng Astral ( 𝌆
) (được biểu thị bằng các cặp thay thế trong JavaScript ) và dấu kết hợp ( ñ
cuối cùng mañana
thực sự bao gồm hai biểu tượng: U + 006E LATIN SMALL LETTER N và U + 0303 COMBINING TILDE).
Thứ tự xuất hiện các cặp thay thế xuất hiện không thể đảo ngược, nếu không thì biểu tượng thiên văn sẽ không xuất hiện nữa trong chuỗi 'đảo ngược'. Đó là lý do tại sao bạn thấy những ��
dấu hiệu đó trong đầu ra cho ví dụ trước.
Các dấu kết hợp luôn được áp dụng cho biểu tượng trước đó, do đó, bạn phải coi cả biểu tượng chính (U + 006E LATIN SMALL LETTER N) là toàn bộ dấu kết hợp (U + 0303 COMBINING TILDE). Đảo ngược thứ tự của chúng sẽ làm cho dấu kết hợp được ghép với một biểu tượng khác trong chuỗi. Đó là lý do tại sao đầu ra ví dụ có ã
thay vì ñ
.
Hy vọng, điều này giải thích tại sao tất cả các câu trả lời được đăng cho đến nay là sai .
Để trả lời câu hỏi ban đầu của bạn - cách [đúng] đảo ngược một chuỗi trong JavaScript -, tôi đã viết một thư viện JavaScript nhỏ có khả năng đảo ngược chuỗi nhận biết Unicode. Nó không có bất kỳ vấn đề nào tôi vừa đề cập. Thư viện được gọi là Esrever ; mã của nó là trên GitHub và nó hoạt động trong hầu hết mọi môi trường JavaScript. Nó đi kèm với một tiện ích shell / nhị phân, vì vậy bạn có thể dễ dàng đảo ngược chuỗi từ thiết bị đầu cuối của bạn nếu bạn muốn.
var input = 'foo 𝌆 bar mañana mañana';
esrever.reverse(input);
// → 'anañam anañam rab 𝌆 oof'
Đối với phần của điểm tại chỗ, hãy xem các câu trả lời khác.
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}
hoặc là
String.prototype.reverse_string = function() {
var s = "";
var i = this.length;
while (i>0) {
s += this.substring(i-1,i);
i--;
}
return s;
}
Phân tích chi tiết và mười cách khác nhau để đảo ngược một chuỗi và chi tiết hiệu suất của chúng.
http://eddmann.com/posts/ten-ways-to-reverse-a-opes-in-javascript/
Hiệu quả của những triển khai này:
(Các) triển khai thực hiện tốt nhất trên mỗi trình duyệt
Dưới đây là những triển khai:
Thực hiện 1:
function reverse(s) {
var o = '';
for (var i = s.length - 1; i >= 0; i--)
o += s[i];
return o;
}
Thực hiện 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('');
}
Thực hiện 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('');
}
Thực hiện 4:
function reverse(s) {
return s.split('').reverse().join('');
}
Thực hiện 5:
function reverse(s) {
var i = s.length,
o = '';
while (i > 0) {
o += s.substring(i - 1, i);
i--;
}
return o;
}
Thực hiện 6:
function reverse(s) {
for (var i = s.length - 1, o = ''; i >= 0; o += s[i--]) { }
return o;
}
Thực hiện 7:
function reverse(s) {
return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}
Thực hiện 8:
function reverse(s) {
function rev(s, len, o) {
return (len === 0) ? o : rev(s, --len, (o += s[len]));
};
return rev(s, s.length, '');
}
Thực hiện 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('');
}
Thực hiện 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));
}
Toàn bộ "đảo ngược một chuỗi tại chỗ" là một câu hỏi phỏng vấn cổ của các lập trình viên C, và những người được họ phỏng vấn (để trả thù, có thể?), Sẽ hỏi. Thật không may, đó là phần "Tại chỗ" không còn hoạt động vì các chuỗi trong hầu hết mọi ngôn ngữ được quản lý (JS, C #, v.v.) sử dụng các chuỗi bất biến, do đó đánh bại toàn bộ ý tưởng di chuyển một chuỗi mà không phân bổ bất kỳ bộ nhớ mới nào.
Mặc dù các giải pháp ở trên thực sự đảo ngược một chuỗi, nhưng chúng không làm điều đó mà không phân bổ thêm bộ nhớ và do đó không thỏa mãn các điều kiện. Bạn cần có quyền truy cập trực tiếp vào chuỗi như được phân bổ và có thể thao tác vị trí bộ nhớ ban đầu của nó để có thể đảo ngược nó tại chỗ.
Cá nhân, tôi thực sự ghét những loại câu hỏi phỏng vấn này, nhưng thật đáng buồn, tôi chắc chắn rằng chúng ta sẽ tiếp tục gặp chúng trong nhiều năm tới.
Đầu tiên, sử dụng Array.from()
để biến một chuỗi thành một mảng, sau đó Array.prototype.reverse()
đảo ngược mảng và sau đó Array.prototype.join()
làm cho nó trở lại một chuỗi.
const reverse = str => Array.from(str).reverse().join('');
reverse
logic có sẵn .
string.split('')
không hoạt động. Xem câu trả lời này để giải thích thêm.
Array.from('foo 𝌆 bar mañana mañana').reverse().join('') == 'anãnam anañam rab 𝌆 oof'
Array.from('foo 𝌆 bar mañana mañana'.normalize('NFC')).reverse().join('')
sẽ trở thành"anañam anañam rab 𝌆 oof"
Trong ECMAScript 6, bạn có thể đảo ngược chuỗi nhanh hơn mà không cần sử dụng .split('')
phương thức phân tách, với toán tử trải rộng như vậy:
var str = [...'racecar'].reverse().join('');
string.split('')
là rõ ràng cho hầu hết mọi người hơn [...string]
.
.split('')
có vấn đề với các ký tự từ các mặt phẳng bổ sung (các cặp thay thế trong UTF-16), vì nó phân tách theo đơn vị mã UTF-16 thay vì điểm mã . Toán tử lây lan và Array.from()
(ưu tiên của tôi) không.
Có vẻ như tôi trễ 3 năm đến bữa tiệc ...
Thật không may, bạn không thể như đã được chỉ ra. Xem chuỗi JavaScript có bất biến không? Tôi có cần một "trình tạo chuỗi" trong JavaScript không?
Điều tốt nhất tiếp theo bạn có thể làm là tạo một "khung nhìn" hoặc "trình bao bọc", lấy một chuỗi và giới thiệu lại bất kỳ phần nào của API chuỗi bạn đang sử dụng, nhưng giả vờ chuỗi bị đảo ngược. Ví dụ:
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
Bản giới thiệu:
> 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"
Các kicker - sau đây được thực hiện tại chỗ bằng toán học thuần túy, chỉ truy cập mỗi nhân vật một lần và chỉ khi cần thiết:
> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"
> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"
Điều này mang lại khoản tiết kiệm đáng kể nếu áp dụng cho một chuỗi rất lớn, nếu bạn chỉ lấy một lát tương đối nhỏ.
Điều này có đáng hay không (đảo ngược như một bản sao như trong hầu hết các ngôn ngữ lập trình) tùy thuộc vào trường hợp sử dụng của bạn và cách bạn thực hiện lại chuỗi API hiệu quả. Ví dụ: nếu tất cả những gì bạn muốn là thực hiện thao tác chỉ mục chuỗi hoặc lấy slice
s hoặc s nhỏ substr
, điều này sẽ giúp bạn tiết kiệm không gian và thời gian. Tuy nhiên, nếu bạn dự định in các lát hoặc lớp nền đảo ngược lớn, thì khoản tiết kiệm có thể thực sự nhỏ, thậm chí còn tệ hơn so với việc thực hiện một bản sao đầy đủ. Chuỗi "đảo ngược" của bạn cũng sẽ không có kiểu string
, mặc dù bạn có thể giả mạo chuỗi này bằng nguyên mẫu.
Việc triển khai demo ở trên tạo ra một đối tượng mới có kiểu ReversedString. Nó được tạo nguyên mẫu, và do đó khá hiệu quả, với công việc gần như tối thiểu và không gian tối thiểu (định nghĩa nguyên mẫu được chia sẻ). Đó là một thực hiện lười biếng liên quan đến cắt lát hoãn lại. Bất cứ khi nào bạn thực hiện một chức năng như .slice
hoặc .reversed
, nó sẽ thực hiện chỉ số toán học. Cuối cùng khi bạn trích xuất dữ liệu (bằng cách gọi ngầm .toString()
hoặc.charCodeAt(...)
hoặc một cái gì đó), nó sẽ áp dụng những dữ liệu đó theo cách "thông minh", chạm vào ít dữ liệu nhất có thể.
Lưu ý: API chuỗi trên là một ví dụ và có thể không được triển khai hoàn hảo. Bạn cũng có thể sử dụng chỉ 1-2 chức năng mà bạn cần.
Có nhiều cách bạn có thể đảo ngược một chuỗi trong JavaScript. Tôi đang ghi lại ba cách tôi thích.
Cách tiếp cận 1: Sử dụng chức năng đảo ngược:
function reverse(str) {
return str.split('').reverse().join('');
}
Cách tiếp cận 2: Vòng qua các ký tự:
function reverse(str) {
let reversed = '';
for (let character of str) {
reversed = character + reversed;
}
return reversed;
}
Cách tiếp cận 3: Sử dụng chức năng giảm:
function reverse(str) {
return str.split('').reduce((rev, char) => char + rev, '');
}
Tôi hi vọng cái này giúp được :)
Trong một cuộc phỏng vấn, tôi được yêu cầu đảo ngược một chuỗi mà không sử dụng bất kỳ biến hoặc phương thức riêng nào. Đây là triển khai yêu thích của tôi:
function reverseString(str) {
return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}
slice
? : - /
Array.prototype.reverse()
.
Có nhiều cách để làm điều đó, bạn có thể kiểm tra như sau,
1. Vòng lặp truyền thống (tăng dần):
function reverseString(str){
let stringRev ="";
for(let i= 0; i<str.length; i++){
stringRev = str[i]+stringRev;
}
return stringRev;
}
alert(reverseString("Hello World!"));
2. Vòng lặp truyền thống (giảm dần):
function reverseString(str){
let revstr = "";
for(let i = str.length-1; i>=0; i--){
revstr = revstr+ str[i];
}
return revstr;
}
alert(reverseString("Hello World!"));
3. Sử dụng vòng lặp for-of
function reverseString(str){
let strn ="";
for(let char of str){
strn = char + strn;
}
return strn;
}
alert(reverseString("Get well soon"));
4. Sử dụng phương thức mảng forEach / thứ tự cao:
function reverseString(str){
let revSrring = "";
str.split("").forEach(function(char){
revSrring = char + revSrring;
});
return revSrring;
}
alert(reverseString("Learning JavaScript"));
5. Tiêu chuẩn ES6:
function reverseString(str){
let revSrring = "";
str.split("").forEach(char => revSrring = char + revSrring);
return revSrring;
}
alert(reverseString("Learning JavaScript"));
6. Cách mới nhất:
function reverseString(str){
return str.split("").reduce(function(revString, char){
return char + revString;
}, "");
}
alert(reverseString("Learning JavaScript"));
7. Bạn cũng có thể nhận được kết quả bằng cách sử dụng sau đây,
function reverseString(str){
return str.split("").reduce((revString, char)=> char + revString, "");
}
alert(reverseString("Learning JavaScript"));
Trong ES6, bạn có thêm một tùy chọn
function reverseString (str) {
return [...str].reverse().join('')
}
reverseString('Hello');
Đây là cách dễ nhất tôi nghĩ
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 🍺'));
Array.prototype.reverse()
đó sẽ là cách dễ nhất, do đó là câu trả lời phổ biến nhất. Tất nhiên, nó sẽ đòi hỏi kiến thức tốt về JavaScript.
Tôi biết rằng đây là một câu hỏi cũ đã được trả lời tốt, nhưng để giải trí cho riêng tôi, tôi đã viết chức năng đảo ngược sau đây và nghĩ rằng tôi sẽ chia sẻ nó trong trường hợp nó hữu ích cho bất kỳ ai khác. Nó xử lý cả cặp thay thế và dấu kết hợp:
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('');
}
Tất cả các đạo cụ cho Mathias, Punycode và nhiều tài liệu tham khảo khác để dạy tôi về sự phức tạp của mã hóa ký tự trong JavaScript.
Bạn không thể bởi vì các chuỗi JS là bất biến. Giải pháp không tại chỗ ngắn
[...str].reverse().join``
Nếu bạn không muốn sử dụng bất kỳ chức năng tích hợp nào. Thử cái này
var string = 'abcdefg';
var newstring = '';
for(let i = 0; i < string.length; i++){
newstring = string[i] += newstring;
}
console.log(newstring);
Câu trả lời thực sự là: bạn không thể đảo ngược nó tại chỗ, nhưng bạn có thể tạo một chuỗi mới ngược lại.
Cũng giống như một bài tập để chơi với đệ quy: đôi khi khi bạn đi phỏng vấn, người phỏng vấn có thể hỏi bạn cách thực hiện điều này bằng cách sử dụng đệ quy và tôi nghĩ "câu trả lời ưa thích" có thể là "Tôi không muốn làm điều này trong đệ quy có thể dễ dàng gây ra tràn ngăn xếp "(bởi vì nó O(n)
đúng hơn O(log n)
. Nếu có O(log n)
, khá khó khăn để có được tràn ngăn xếp - 4 tỷ mục có thể được xử lý bởi cấp độ ngăn xếp là 32, vì 2 ** 32 là 4294967296. Nhưng nếu nó làO(n)
, nó có thể dễ dàng bị tràn stack.
Đôi khi người phỏng vấn vẫn sẽ hỏi bạn, "giống như một bài tập, tại sao bạn vẫn không viết nó bằng cách sử dụng đệ quy?" Và đây là:
String.prototype.reverse = function() {
if (this.length <= 1) return this;
else return this.slice(1).reverse() + this.slice(0,1);
}
chạy thử nghiệm:
var s = "";
for(var i = 0; i < 1000; i++) {
s += ("apple" + i);
}
console.log(s.reverse());
đầu ra:
999elppa899elppa...2elppa1elppa0elppa
Để thử tràn ngăn xếp, tôi đã đổi 1000
thành 10000
Google Chrome và báo cáo:
RangeError: Maximum call stack size exceeded
//es6
//array.from
const reverseString = (string) => Array.from(string).reduce((a, e) => e + a);
//split
const reverseString = (string) => string.split('').reduce((a, e) => e + a);
//split problem
"𠜎𠺢".split('')[0] === Array.from("𠜎𠺢")[0] // "�" === "𠜎" => false
"😂😹🤗".split('')[0] === Array.from("😂😹🤗")[0] // "�" === "😂" => false
Một hàm nhỏ xử lý cả kết hợp dấu phụ và ký tự 2 byte:
(function(){
var isCombiningDiacritic = function( code )
{
return (0x0300 <= code && code <= 0x036F) // Comb. Diacritical Marks
|| (0x1AB0 <= code && code <= 0x1AFF) // Comb. Diacritical Marks Extended
|| (0x1DC0 <= code && code <= 0x1DFF) // Comb. Diacritical Marks Supplement
|| (0x20D0 <= code && code <= 0x20FF) // Comb. Diacritical Marks for Symbols
|| (0xFE20 <= code && code <= 0xFE2F); // Comb. Half Marks
};
String.prototype.reverse = function()
{
var output = "",
i = this.length - 1,
width;
for ( ; i >= 0; --i )
{
width = 1;
while( i > 0 && isCombiningDiacritic( this.charCodeAt(i) ) )
{
--i;
width++;
}
if (
i > 0
&& "\uDC00" <= this[i] && this[i] <= "\uDFFF"
&& "\uD800" <= this[i-1] && this[i-1] <= "\uDBFF"
)
{
--i;
width++;
}
output += this.substr( i, width );
}
return output;
}
})();
// Tests
[
'abcdefg',
'ab\u0303c',
'a\uD83C\uDFA5b',
'a\uD83C\uDFA5b\uD83C\uDFA6c',
'a\uD83C\uDFA5b\u0306c\uD83C\uDFA6d',
'TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚N̐Y̡' // copied from http://stackoverflow.com/a/1732454/1509264
].forEach(
function(str){ console.log( str + " -> " + str.reverse() ); }
);
Cập nhật
Một danh sách đầy đủ hơn về kết hợp dấu phụ là:
var isCombiningDiacritic = function( code )
{
return (0x0300 <= code && code <= 0x036F)
|| (0x0483 <= code && code <= 0x0489)
|| (0x0591 <= code && code <= 0x05BD)
|| (code == 0x05BF)
|| (0x05C1 <= code && code <= 0x05C2)
|| (0x05C4 <= code && code <= 0x05C5)
|| (code == 0x05C7)
|| (0x0610 <= code && code <= 0x061A)
|| (0x064B <= code && code <= 0x065F)
|| (code == 0x0670)
|| (0x06D6 <= code && code <= 0x06DC)
|| (0x06DF <= code && code <= 0x06E4)
|| (0x06E7 <= code && code <= 0x06E8)
|| (0x06EA <= code && code <= 0x06ED)
|| (code == 0x0711)
|| (0x0730 <= code && code <= 0x074A)
|| (0x07A6 <= code && code <= 0x07B0)
|| (0x07EB <= code && code <= 0x07F3)
|| (code == 0x07FD)
|| (0x0816 <= code && code <= 0x0819)
|| (0x081B <= code && code <= 0x0823)
|| (0x0825 <= code && code <= 0x0827)
|| (0x0829 <= code && code <= 0x082D)
|| (0x0859 <= code && code <= 0x085B)
|| (0x08D3 <= code && code <= 0x08E1)
|| (0x08E3 <= code && code <= 0x0902)
|| (code == 0x093A)
|| (code == 0x093C)
|| (0x0941 <= code && code <= 0x0948)
|| (code == 0x094D)
|| (0x0951 <= code && code <= 0x0957)
|| (0x0962 <= code && code <= 0x0963)
|| (code == 0x0981)
|| (code == 0x09BC)
|| (0x09C1 <= code && code <= 0x09C4)
|| (code == 0x09CD)
|| (0x09E2 <= code && code <= 0x09E3)
|| (0x09FE <= code && code <= 0x0A02)
|| (code == 0x0A3C)
|| (0x0A41 <= code && code <= 0x0A51)
|| (0x0A70 <= code && code <= 0x0A71)
|| (code == 0x0A75)
|| (0x0A81 <= code && code <= 0x0A82)
|| (code == 0x0ABC)
|| (0x0AC1 <= code && code <= 0x0AC8)
|| (code == 0x0ACD)
|| (0x0AE2 <= code && code <= 0x0AE3)
|| (0x0AFA <= code && code <= 0x0B01)
|| (code == 0x0B3C)
|| (code == 0x0B3F)
|| (0x0B41 <= code && code <= 0x0B44)
|| (0x0B4D <= code && code <= 0x0B56)
|| (0x0B62 <= code && code <= 0x0B63)
|| (code == 0x0B82)
|| (code == 0x0BC0)
|| (code == 0x0BCD)
|| (code == 0x0C00)
|| (code == 0x0C04)
|| (0x0C3E <= code && code <= 0x0C40)
|| (0x0C46 <= code && code <= 0x0C56)
|| (0x0C62 <= code && code <= 0x0C63)
|| (code == 0x0C81)
|| (code == 0x0CBC)
|| (0x0CCC <= code && code <= 0x0CCD)
|| (0x0CE2 <= code && code <= 0x0CE3)
|| (0x0D00 <= code && code <= 0x0D01)
|| (0x0D3B <= code && code <= 0x0D3C)
|| (0x0D41 <= code && code <= 0x0D44)
|| (code == 0x0D4D)
|| (0x0D62 <= code && code <= 0x0D63)
|| (code == 0x0DCA)
|| (0x0DD2 <= code && code <= 0x0DD6)
|| (code == 0x0E31)
|| (0x0E34 <= code && code <= 0x0E3A)
|| (0x0E47 <= code && code <= 0x0E4E)
|| (code == 0x0EB1)
|| (0x0EB4 <= code && code <= 0x0EBC)
|| (0x0EC8 <= code && code <= 0x0ECD)
|| (0x0F18 <= code && code <= 0x0F19)
|| (code == 0x0F35)
|| (code == 0x0F37)
|| (code == 0x0F39)
|| (0x0F71 <= code && code <= 0x0F7E)
|| (0x0F80 <= code && code <= 0x0F84)
|| (0x0F86 <= code && code <= 0x0F87)
|| (0x0F8D <= code && code <= 0x0FBC)
|| (code == 0x0FC6)
|| (0x102D <= code && code <= 0x1030)
|| (0x1032 <= code && code <= 0x1037)
|| (0x1039 <= code && code <= 0x103A)
|| (0x103D <= code && code <= 0x103E)
|| (0x1058 <= code && code <= 0x1059)
|| (0x105E <= code && code <= 0x1060)
|| (0x1071 <= code && code <= 0x1074)
|| (code == 0x1082)
|| (0x1085 <= code && code <= 0x1086)
|| (code == 0x108D)
|| (code == 0x109D)
|| (0x135D <= code && code <= 0x135F)
|| (0x1712 <= code && code <= 0x1714)
|| (0x1732 <= code && code <= 0x1734)
|| (0x1752 <= code && code <= 0x1753)
|| (0x1772 <= code && code <= 0x1773)
|| (0x17B4 <= code && code <= 0x17B5)
|| (0x17B7 <= code && code <= 0x17BD)
|| (code == 0x17C6)
|| (0x17C9 <= code && code <= 0x17D3)
|| (code == 0x17DD)
|| (0x180B <= code && code <= 0x180D)
|| (0x1885 <= code && code <= 0x1886)
|| (code == 0x18A9)
|| (0x1920 <= code && code <= 0x1922)
|| (0x1927 <= code && code <= 0x1928)
|| (code == 0x1932)
|| (0x1939 <= code && code <= 0x193B)
|| (0x1A17 <= code && code <= 0x1A18)
|| (code == 0x1A1B)
|| (code == 0x1A56)
|| (0x1A58 <= code && code <= 0x1A60)
|| (code == 0x1A62)
|| (0x1A65 <= code && code <= 0x1A6C)
|| (0x1A73 <= code && code <= 0x1A7F)
|| (0x1AB0 <= code && code <= 0x1B03)
|| (code == 0x1B34)
|| (0x1B36 <= code && code <= 0x1B3A)
|| (code == 0x1B3C)
|| (code == 0x1B42)
|| (0x1B6B <= code && code <= 0x1B73)
|| (0x1B80 <= code && code <= 0x1B81)
|| (0x1BA2 <= code && code <= 0x1BA5)
|| (0x1BA8 <= code && code <= 0x1BA9)
|| (0x1BAB <= code && code <= 0x1BAD)
|| (code == 0x1BE6)
|| (0x1BE8 <= code && code <= 0x1BE9)
|| (code == 0x1BED)
|| (0x1BEF <= code && code <= 0x1BF1)
|| (0x1C2C <= code && code <= 0x1C33)
|| (0x1C36 <= code && code <= 0x1C37)
|| (0x1CD0 <= code && code <= 0x1CD2)
|| (0x1CD4 <= code && code <= 0x1CE0)
|| (0x1CE2 <= code && code <= 0x1CE8)
|| (code == 0x1CED)
|| (code == 0x1CF4)
|| (0x1CF8 <= code && code <= 0x1CF9)
|| (0x1DC0 <= code && code <= 0x1DFF)
|| (0x20D0 <= code && code <= 0x20F0)
|| (0x2CEF <= code && code <= 0x2CF1)
|| (code == 0x2D7F)
|| (0x2DE0 <= code && code <= 0x2DFF)
|| (0x302A <= code && code <= 0x302D)
|| (0x3099 <= code && code <= 0x309A)
|| (0xA66F <= code && code <= 0xA672)
|| (0xA674 <= code && code <= 0xA67D)
|| (0xA69E <= code && code <= 0xA69F)
|| (0xA6F0 <= code && code <= 0xA6F1)
|| (code == 0xA802)
|| (code == 0xA806)
|| (code == 0xA80B)
|| (0xA825 <= code && code <= 0xA826)
|| (0xA8C4 <= code && code <= 0xA8C5)
|| (0xA8E0 <= code && code <= 0xA8F1)
|| (code == 0xA8FF)
|| (0xA926 <= code && code <= 0xA92D)
|| (0xA947 <= code && code <= 0xA951)
|| (0xA980 <= code && code <= 0xA982)
|| (code == 0xA9B3)
|| (0xA9B6 <= code && code <= 0xA9B9)
|| (0xA9BC <= code && code <= 0xA9BD)
|| (code == 0xA9E5)
|| (0xAA29 <= code && code <= 0xAA2E)
|| (0xAA31 <= code && code <= 0xAA32)
|| (0xAA35 <= code && code <= 0xAA36)
|| (code == 0xAA43)
|| (code == 0xAA4C)
|| (code == 0xAA7C)
|| (code == 0xAAB0)
|| (0xAAB2 <= code && code <= 0xAAB4)
|| (0xAAB7 <= code && code <= 0xAAB8)
|| (0xAABE <= code && code <= 0xAABF)
|| (code == 0xAAC1)
|| (0xAAEC <= code && code <= 0xAAED)
|| (code == 0xAAF6)
|| (code == 0xABE5)
|| (code == 0xABE8)
|| (code == 0xABED)
|| (code == 0xFB1E)
|| (0xFE00 <= code && code <= 0xFE0F)
|| (0xFE20 <= code && code <= 0xFE2F)
|| (code == 0x101FD)
|| (code == 0x102E0)
|| (0x10376 <= code && code <= 0x1037A)
|| (0x10A01 <= code && code <= 0x10A0F)
|| (0x10A38 <= code && code <= 0x10A3F)
|| (0x10AE5 <= code && code <= 0x10AE6)
|| (0x10D24 <= code && code <= 0x10D27)
|| (0x10F46 <= code && code <= 0x10F50)
|| (code == 0x11001)
|| (0x11038 <= code && code <= 0x11046)
|| (0x1107F <= code && code <= 0x11081)
|| (0x110B3 <= code && code <= 0x110B6)
|| (0x110B9 <= code && code <= 0x110BA)
|| (0x11100 <= code && code <= 0x11102)
|| (0x11127 <= code && code <= 0x1112B)
|| (0x1112D <= code && code <= 0x11134)
|| (code == 0x11173)
|| (0x11180 <= code && code <= 0x11181)
|| (0x111B6 <= code && code <= 0x111BE)
|| (0x111C9 <= code && code <= 0x111CC)
|| (0x1122F <= code && code <= 0x11231)
|| (code == 0x11234)
|| (0x11236 <= code && code <= 0x11237)
|| (code == 0x1123E)
|| (code == 0x112DF)
|| (0x112E3 <= code && code <= 0x112EA)
|| (0x11300 <= code && code <= 0x11301)
|| (0x1133B <= code && code <= 0x1133C)
|| (code == 0x11340)
|| (0x11366 <= code && code <= 0x11374)
|| (0x11438 <= code && code <= 0x1143F)
|| (0x11442 <= code && code <= 0x11444)
|| (code == 0x11446)
|| (code == 0x1145E)
|| (0x114B3 <= code && code <= 0x114B8)
|| (code == 0x114BA)
|| (0x114BF <= code && code <= 0x114C0)
|| (0x114C2 <= code && code <= 0x114C3)
|| (0x115B2 <= code && code <= 0x115B5)
|| (0x115BC <= code && code <= 0x115BD)
|| (0x115BF <= code && code <= 0x115C0)
|| (0x115DC <= code && code <= 0x115DD)
|| (0x11633 <= code && code <= 0x1163A)
|| (code == 0x1163D)
|| (0x1163F <= code && code <= 0x11640)
|| (code == 0x116AB)
|| (code == 0x116AD)
|| (0x116B0 <= code && code <= 0x116B5)
|| (code == 0x116B7)
|| (0x1171D <= code && code <= 0x1171F)
|| (0x11722 <= code && code <= 0x11725)
|| (0x11727 <= code && code <= 0x1172B)
|| (0x1182F <= code && code <= 0x11837)
|| (0x11839 <= code && code <= 0x1183A)
|| (0x119D4 <= code && code <= 0x119DB)
|| (code == 0x119E0)
|| (0x11A01 <= code && code <= 0x11A06)
|| (0x11A09 <= code && code <= 0x11A0A)
|| (0x11A33 <= code && code <= 0x11A38)
|| (0x11A3B <= code && code <= 0x11A3E)
|| (code == 0x11A47)
|| (0x11A51 <= code && code <= 0x11A56)
|| (0x11A59 <= code && code <= 0x11A5B)
|| (0x11A8A <= code && code <= 0x11A96)
|| (0x11A98 <= code && code <= 0x11A99)
|| (0x11C30 <= code && code <= 0x11C3D)
|| (0x11C92 <= code && code <= 0x11CA7)
|| (0x11CAA <= code && code <= 0x11CB0)
|| (0x11CB2 <= code && code <= 0x11CB3)
|| (0x11CB5 <= code && code <= 0x11CB6)
|| (0x11D31 <= code && code <= 0x11D45)
|| (code == 0x11D47)
|| (0x11D90 <= code && code <= 0x11D91)
|| (code == 0x11D95)
|| (code == 0x11D97)
|| (0x11EF3 <= code && code <= 0x11EF4)
|| (0x16AF0 <= code && code <= 0x16AF4)
|| (0x16B30 <= code && code <= 0x16B36)
|| (code == 0x16F4F)
|| (0x16F8F <= code && code <= 0x16F92)
|| (0x1BC9D <= code && code <= 0x1BC9E)
|| (0x1D167 <= code && code <= 0x1D169)
|| (0x1D17B <= code && code <= 0x1D182)
|| (0x1D185 <= code && code <= 0x1D18B)
|| (0x1D1AA <= code && code <= 0x1D1AD)
|| (0x1D242 <= code && code <= 0x1D244)
|| (0x1DA00 <= code && code <= 0x1DA36)
|| (0x1DA3B <= code && code <= 0x1DA6C)
|| (code == 0x1DA75)
|| (code == 0x1DA84)
|| (0x1DA9B <= code && code <= 0x1E02A)
|| (0x1E130 <= code && code <= 0x1E136)
|| (0x1E2EC <= code && code <= 0x1E2EF)
|| (0x1E8D0 <= code && code <= 0x1E8D6)
|| (0x1E944 <= code && code <= 0x1E94A)
|| (0xE0100 <= code && code <= 0xE01EF);
};
isCombiningDiacritic
chức năng để bao gồm tất cả phạm vi 316; vui lòng cung cấp chỉnh sửa đó vì bạn dường như có dữ liệu trong tay.
function reverseString(string) {
var reversedString = "";
var stringLength = string.length - 1;
for (var i = stringLength; i >= 0; i--) {
reversedString += string[i];
}
return reversedString;
}
không chuyển đổi chuỗi thành mảng;
String.prototype.reverse = function() {
var ret = "";
var size = 0;
for (var i = this.length - 1; -1 < i; i -= size) {
if (
'\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' &&
'\uDC00' <= this[i] && this[i] <= '\uDFFF'
) {
size = 2;
ret += this[i - 1] + this[i];
} else {
size = 1;
ret += this[i];
}
}
return ret;
}
console.log('anãnam anañam' === 'mañana mañana'.reverse());
sử dụng Array.reverse mà không chuyển đổi ký tự thành điểm mã;
String.prototype.reverse = function() {
var array = this.split("").reverse();
for (var i = 0; i < this.length; ++i) {
if (
'\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' &&
'\uDC00' <= this[i] && this[i] <= '\uDFFF'
) {
array[i - 1] = array[i - 1] + array[i];
array[i] = array[i - 1].substr(0, 1);
array[i - 1] = array[i - 1].substr(1, 1);
}
}
return array.join("");
}
console.log('anãnam anañam' === 'mañana mañana'.reverse());
var c = array[i-1]; array[i-1] = array[i]; array[i] = c;
không yêu cầu ghép cặp mã. Ngoài ra, vòng lặp for sẽ bắt đầu lúc 1.
'\ud83c\ud83c\udfa5'.reverse()
- nó sẽ xuất ra giống như đầu vào. Thêm vào ++i;
trong if
tuyên bố nên sửa lỗi này.
'a\u0303bc'.reverse() === 'cba\u0303'
nên trả về đúng.
Tôi nghĩ String.prototype.reverse là một cách tốt để giải quyết vấn đề này; mã như dưới đây;
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";
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);
Nỗ lực ban đầu của riêng tôi ...
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"
Giữ nó KHÔ và đơn giản ngớ ngẩn !!
function reverse(s){
let str = s;
var reverse = '';
for (var i=str.length;i>0;i--){
var newstr = str.substring(0,i)
reverse += newstr.substr(-1,1)
}
return reverse;
}
OK, khá đơn giản, bạn có thể tạo một hàm với một vòng lặp đơn giản để thực hiện đảo ngược chuỗi cho bạn mà không cần sử dụng reverse()
, charAt()
v.v. như thế này:
Ví dụ: bạn có chuỗi này:
var name = "StackOverflow";
Tạo một chức năng như thế này, tôi gọi nó là reverseString
...
function reverseString(str) {
if(!str.trim() || 'string' !== typeof str) {
return;
}
let l=str.length, s='';
while(l > 0) {
l--;
s+= str[l];
}
return s;
}
Và bạn có thể gọi nó như:
reverseString(name);
Và kết quả sẽ là:
"wolfrevOkcatS"
Cách tốt nhất để đảo ngược một chuỗi trong JavaScript
1) Array.reverse:
Có lẽ bạn đang suy nghĩ, chờ đã, tôi nghĩ rằng chúng ta đang đảo ngược một chuỗi, tại sao bạn lại sử dụng phương thức Array.reverse. Sử dụng phương thức String.split, chúng tôi đang chuyển đổi chuỗi của mình thành một mảng các ký tự. Sau đó, chúng tôi đang đảo ngược thứ tự của từng giá trị trong mảng và cuối cùng chúng tôi chuyển đổi Mảng trở lại thành Chuỗi bằng phương thức Array.join.
function reverseString(str) {
return str.split('').reverse().join('');
}
reverseString('dwayne');
2) Giảm vòng lặp while:
Mặc dù khá dài dòng, giải pháp này có ưu điểm so với giải pháp một. Bạn không tạo một mảng và bạn chỉ nối một chuỗi dựa trên các ký tự từ chuỗi nguồn.
Từ góc độ hiệu suất, điều này có thể sẽ mang lại kết quả tốt nhất (mặc dù chưa được kiểm tra). Đối với các chuỗi cực dài, mặc dù hiệu suất có thể giảm ra khỏi cửa sổ.
function reverseString(str) {
var temp = '';
var i = str.length;
while (i > 0) {
temp += str.substring(i - 1, i);
i--;
}
return temp;
}
reverseString('dwayne');
3) Đệ quy
Tôi thích cách đơn giản và rõ ràng giải pháp này là. Bạn có thể thấy rõ rằng các phương thức String.charAt và String.substr đang được sử dụng để truyền qua một giá trị khác nhau bằng cách gọi chính nó mỗi lần cho đến khi chuỗi trống mà ternary sẽ trả về một chuỗi rỗng thay vì sử dụng đệ quy để gọi chính nó . Điều này có thể sẽ mang lại hiệu suất tốt thứ hai sau giải pháp thứ hai.
function reverseString(str) {
return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');