Làm cách nào tôi có thể xử lý từng chữ cái của văn bản bằng Javascript?


362

Tôi muốn thông báo cho từng chữ cái riêng lẻ của một chuỗi, nhưng tôi không chắc làm thế nào để làm điều này.

Vì vậy, nếu tôi có:

var str = 'This is my string';

Tôi muốn có thể cảnh báo riêng T, h, i, s, v.v ... Đây chỉ là khởi đầu của một ý tưởng mà tôi đang thực hiện, nhưng tôi cần biết cách xử lý từng chữ cái riêng biệt.

Tôi muốn sử dụng jQuery và nghĩ rằng tôi có thể cần phải sử dụng hàm split sau khi kiểm tra độ dài của chuỗi.

Ý tưởng?


3
Có thể bạn đang tìm kiếm điều này: kể từ ES6, có for(const c of str) { ... }. Nhiều hơn thế nữa dưới đây trong một câu trả lời khá chi tiết nhưng không đủ nâng cao. PS: Liên kết của @ ARJUN không hoạt động với tôi.
Tối đa

Câu trả lời:


421

Nếu thứ tự cảnh báo có vấn đề, hãy sử dụng điều này:

for (var i = 0; i < str.length; i++) {
  alert(str.charAt(i));
}

Nếu thứ tự cảnh báo không thành vấn đề, hãy sử dụng:

var i = str.length;
while (i--) {
  alert(str.charAt(i));
}


2
sử dụng []để lấy char ở một vị trí cụ thể không được hỗ trợ trong IE <9
vsync

13
như được đề cập trong câu trả lời khác, bạn có thể sử dụng str.charAt (i) thay cho [] 's. để biết thêm về lý do tại sao bạn nên sử dụng charAt so với [], xem chuỗi.charAt (x) hoặc chuỗi [x]
Julian Soro

12
Tôi thấy khó tin rằng bất kỳ trình biên dịch JS hiện đại nào cũng sẽ tính lại độ dài nếu chuỗi không được sửa đổi bên trong vòng lặp. Trong mọi ngôn ngữ khác, tôi rất vui khi thực hiện kiểm tra độ dài trong mệnh đề kiểm tra của vòng lặp for, giả sử trình biên dịch biết rõ nhất và sẽ tối ưu hóa nó cho phù hợp.
Echelon

3
@Dagmar: Javascript không sử dụng UTF-8, nó sử dụng UTF-16 (hoặc UCS-2, tùy thuộc vào trình duyệt). Mỗi ký tự đơn có thể được biểu diễn dưới dạng UTF-8 hoặc UTF-16 nhưng không gặp phải vấn đề này. Những người duy nhất gặp vấn đề là những người yêu cầu bốn byte trong UTF-16 chứ không phải hai byte. Là ký tự yêu cầu bốn byte trong UTF-16. Các thuật ngữ chính để tìm kiếm thêm thông tin là "mặt phẳng", "không phải BMP" và "cặp thay thế".
hà mã

1
@Dagmar: Cả Java và Javascript đều có chung UTF-16 (trước đây là UCS-). Nền tảng chính thứ ba sử dụng nó là Windows. Các giao thức Unix, MacOS và internet sử dụng UTF-8. charAtcòn sót lại từ UCS-2 ngày khi không có cặp thay thế và để giải quyết vấn đề một chức năng mới, codepointAtđã được thêm vào JavaScript để xử lý chính xác đống poo thân thiện của chúng tôi. Tôi tin rằng Java cũng có nó.
hà mã

240

Có lẽ nhiều hơn là giải quyết. Chỉ muốn đóng góp với một giải pháp đơn giản khác:

var text = 'uololooo';

// With ES6
[...text].forEach(c => console.log(c))

// With the `of` operator
for (const c of text) {
    console.log(c)
}

// With ES5
for (var x = 0, c=''; c = text.charAt(x); x++) { 
    console.log(c); 
}

// ES5 without the for loop:
text.split('').forEach(function(c) {
    console.log(c);
});

4
ví dụ cuối cùng có thể đơn giản là[...text].forEach(console.log)
Govind Rai

10
Không, nó không thể. forEach()vượt qua chỉ mục và mảng là đối số thứ hai và thứ ba. Tôi thà không đăng nhập mà ..
Ông Goferito

1
Lưu ý rằng cả toán tử trải (ví dụ đầu tiên) và lệnh gọi tách (ví dụ cuối) sẽ tạo ra một mảng mới. Điều này thường không phải là một vấn đề, nhưng có thể tốn kém cho các chuỗi lớn hoặc sử dụng thường xuyên.
Randolpho

Thế cònfor (let c of [...text]) { console.log(c) }
Flimm

Với điều đó bạn tạo một mảng mới từ chuỗi. Tôi không thấy lợi ích. let c of textđã làm công việc
Ông Goferito

73

Một giải pháp khả thi trong javascript thuần túy:

for (var x = 0; x < str.length; x++)
{
    var c = str.charAt(x);
    alert(c);
}

Có lẽ sẽ tốt hơn với var x = 0 và var c = str.charAt (x).
Giàu

2
Ngoài ra, str.length nên được lưu trữ trong một biến để nó không phải tiếp tục được truy cập.
Eli Gray

8
@EliGrey Có thực sự quan trọng khi đặt độ dài trong một biến không? Bạn có điểm chuẩn khi điều này sẽ tốt hơn so với việc có ít dòng mã hơn?
pm_labs

@paul_sns Thật thú vị, dường như có một sự khác biệt nhỏ , ít nhất là trong Edge (chênh lệch 0,7ms cho mảng 10000 phần tử): jsfiddle.net/carcigenicate/v8vvjoc1/1 . Có lẽ không phải là một bài kiểm tra hoàn hảo, nhưng nó dựa trên trung bình 10000 bài kiểm tra.
Carcigenicate

1
@paul_sns Thật thú vị, Chrome đã thực hiện thử nghiệm tương tự trong khoảng 2% thời gian (~ 5ms so với ~ 0,0997ms) và cả hai phiên bản đều cho cùng một lúc, nên có vẻ như Edge không được tối ưu hóa.
Carcigenicate

69

Cách xử lý từng chữ cái văn bản (có điểm chuẩn)

https://jsperf.com/str-for-in-of-foreach-map-2

cho

Cổ điển và cho đến nay là một trong những hiệu suất nhất . Bạn nên sử dụng cái này nếu bạn dự định sử dụng nó trong một thuật toán quan trọng về hiệu năng hoặc nó yêu cầu khả năng tương thích tối đa với các phiên bản trình duyệt.

for (var i = 0; i < str.length; i++) {
  console.info(str[i]);
}

cho ... của

cho ... của ES6 mới cho iterator. Được hỗ trợ bởi hầu hết các trình duyệt hiện đại. Nó trực quan hấp dẫn hơn và ít mắc lỗi đánh máy. Nếu bạn đang sử dụng ứng dụng này trong một ứng dụng sản xuất, có lẽ bạn nên sử dụng một bộ chuyển mã như Babel .

let result = '';
for (let letter of str) {
  result += letter;
}

cho mỗi

Phương pháp tiếp cận chức năng . Airbnb đã được phê duyệt . Nhược điểm lớn nhất của việc làm theo cách này là split(), tạo ra một mảng mới để lưu trữ từng chữ cái riêng lẻ của chuỗi.

Tại sao? Điều này thực thi quy tắc bất di bất dịch của chúng tôi. Xử lý các hàm thuần túy trả về các giá trị dễ lý do hơn các tác dụng phụ.

// ES6 version.
let result = '';
str.split('').forEach(letter => {
  result += letter;
});

hoặc là

var result = '';
str.split('').forEach(function(letter) {
  result += letter;
});

Sau đây là những cái tôi không thích.

tại

Không giống như ... của, bạn có được chỉ mục chữ cái thay vì chữ cái. Nó thực hiện khá tệ.

var result = '';
for (var letterIndex in str) {
  result += str[letterIndex];
}

bản đồ

Phương pháp chức năng, đó là tốt. Tuy nhiên, bản đồ không có nghĩa là được sử dụng cho điều đó. Nó nên được sử dụng khi cần thay đổi các giá trị bên trong một mảng, đây không phải là trường hợp.

// ES6 version.
var result = '';
str.split('').map(letter => {
  result += letter;
});

hoặc là

let result = '';
str.split('').map(function(letter) {
  result += letter;
});

1
Trên máy của tôi, forvòng lặp cổ điển thực sự chậm nhất thứ hai, trong khi for...ofnhanh nhất (nhanh gấp khoảng ba lần for).
John Montgomery

1
Điểm chuẩn ở đâu? Giải pháp nhanh nhất là gì?
poitroae

1
@johnywhy Đó là hai năm trước và liên kết đã chết nên tôi không chắc bạn mong tôi bảo vệ kết quả như thế nào khi tôi nhận được. Mặc dù vậy, việc thiết lập một điểm chuẩn mới đồng ý với kết luận của zurfyx, với forvòng lặp nhanh hơn một chút.
John Montgomery

1
@JohnMontermoery Tôi không mong bạn làm gì cả. Chỉ cần một lưu ý cho độc giả tương lai rằng kết quả của bạn khác với câu trả lời. Cá nhân tôi muốn biết kết quả nào áp dụng cho các trình duyệt ngày hôm nay 2020, altho '2018 đã không còn lâu nữa. Liên kết nào đã chết?
johny tại sao

1
@johnywhy Liên kết ở trên cùng với tất cả các bài kiểm tra thực tế đang trả lại 404 cho tôi.
John Montgomery

42

Hầu hết nếu không phải tất cả các câu trả lời ở đây đều sai vì chúng sẽ bị hỏng bất cứ khi nào có một ký tự trong chuỗi bên ngoài Unicode BMP (Mặt phẳng đa ngôn ngữ cơ bản) . Điều đó có nghĩa là tất cả các Emoji sẽ bị phá vỡ .

JavaScript sử dụng UTF- 16 Unicode cho tất cả các chuỗi. Trong UTF-16, các ký tự ngoài BMP được tạo thành hai phần, được gọi là " Cặp thay thế " và hầu hết các câu trả lời ở đây sẽ xử lý từng phần của các cặp như vậy thay vì chỉ một ký tự.

Một cách trong JavaScript hiện đại kể từ ít nhất 2016 là sử dụng Trình lặp chuỗi mới . Đây là ví dụ (gần như) ra khỏi MDN:

var string = 'A\uD835\uDC68B\uD835\uDC69C\uD835\uDC6A';

for (var v of string) {
  alert(v);
}
// "A"
// "\uD835\uDC68"
// "B"
// "\uD835\uDC69"
// "C"
// "\uD835\uDC6A"


4
Để biết giải pháp hiện đại để chia chuỗi thành các ký tự trong khi tính đến các cặp thay thế, hãy xem: stackoverflow.com/a/42596897/527702
hippietrail

20

Bạn có thể thử cái này

var arrValues = 'This is my string'.split('');
// Loop over each value in the array.
$.each(arrValues, function (intIndex, objValue) {
    alert(objValue);
})

11
Vẫn là một lựa chọn, nhưng không biểu diễn. Đừng đặt jQuery ở mọi nơi.
cagatay

10

Thêm một giải pháp ...

var strg= 'This is my string';
for(indx in strg){
  alert(strg[indx]);
}

3
Nếu bạn chỉ muốn char và không phải chỉ mục, sẽ nhanh hơn khi sử dụng for..ofvòng lặpfor (let ch of t) { alert(ch) }
Shaheen Ghiassy

10

Khi tôi cần viết mã ngắn hoặc một lớp lót, tôi sử dụng "hack" này:

'Hello World'.replace(/./g, function (char) {
    alert(char);
    return char; // this is optional 
});

Điều này sẽ không tính các dòng mới để có thể là một điều tốt hoặc xấu. Nếu bạn bao gồm các dòng mới, thay thế: /./bằng /[\S\s]/. Các một lớp lót khác mà bạn có thể thấy có thể sử dụng .split()có nhiều vấn đề


câu trả lời tốt nhất. Đưa vào các vấn đề về tài khoản với unicode và cũng có thể được sử dụng với các cấu trúc chức năng với .map (), v.v.
rofrol

Điều duy nhất tôi không thích ở cái này là khi tôi muốn truy cập vào các thông số bổ sung được truyền cho forEachchức năng của cuộc gọi so với các thông số được gửi trongreplace . Nếu tôi biết tôi là ASCIIing, tôi nghĩ rằng tôi vẫn còn một số trường hợp sử dụng split. Câu trả lời tuyệt vời, mặc dù!
ruffin

Câu trả lời này có phần thưởng với việc chọn trước các giá trị bạn sẽ kiểm tra bằng mọi cách
Fuzzyma

1
Tôi nghĩ rằng điều này sẽ không tính đến các vấn đề Unicode trừ khi nó có ucờ cùng với gcờ? OK chỉ cần thử nghiệm và tôi đã đúng.
hà mã

9

JS mới cho phép điều này:

const str = 'This is my string';
Array.from(str).forEach(alert);

8

Tốt hơn là sử dụng câu lệnh for ..., nếu chuỗi chứa các ký tự unicode, vì kích thước byte khác nhau.

for(var c of "tree 木") { console.log(c); }
//"𝐀A".length === 3

7

Câu trả lời ngắn gọn: Array.from(string)sẽ cung cấp cho bạn những gì bạn có thể muốn và sau đó bạn có thể lặp lại trên đó hoặc bất cứ điều gì vì nó chỉ là một mảng.

ok hãy thử nó với chuỗi này : abc|⚫️\n⚪️|👨‍👩‍👧‍👧.

điểm mã là:

97
98
99
124
9899, 65039
10
9898, 65039
124
128104, 8205, 128105, 8205, 128103, 8205, 128103

vì vậy một số ký tự có một mật mã (byte) và một số có hai hoặc nhiều hơn và một dòng mới được thêm vào để kiểm tra thêm.

Vì vậy, sau khi thử nghiệm có hai cách:

  • byte trên mỗi byte (codepoint mỗi codepoint)
  • nhóm nhân vật (nhưng không phải là biểu tượng cảm xúc của cả gia đình)

string = "abc|⚫️\n⚪️|👨‍👩‍👧‍👧"

console.log({ 'string': string }) // abc|⚫️\n⚪️|👨‍👩‍👧‍👧
console.log({ 'string.length': string.length }) // 21

for (let i = 0; i < string.length; i += 1) {
  console.log({ 'string[i]': string[i] }) // byte per byte
  console.log({ 'string.charAt(i)': string.charAt(i) }) // byte per byte
}

for (let char of string) {
  console.log({ 'for char of string': char }) // character groups
}

for (let char in string) {
  console.log({ 'for char in string': char }) // index of byte per byte
}

string.replace(/./g, (char) => {
  console.log({ 'string.replace(/./g, ...)': char }) // byte per byte
});

string.replace(/[\S\s]/g, (char) => {
  console.log({ 'string.replace(/[\S\s]/g, ...)': char }) // byte per byte
});

[...string].forEach((char) => {
  console.log({ "[...string].forEach": char }) // character groups
})

string.split('').forEach((char) => {
  console.log({ "string.split('').forEach": char }) // byte per byte
})

Array.from(string).forEach((char) => {
  console.log({ "Array.from(string).forEach": char }) // character groups
})

Array.prototype.map.call(string, (char) => {
  console.log({ "Array.prototype.map.call(string, ...)": char }) // byte per byte
})

var regexp = /(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g

string.replace(regexp, (char) => {
  console.log({ 'str.replace(regexp, ...)': char }) // character groups
});


7

Bây giờ bạn có thể lặp lại các điểm mã Unicode riêng lẻ có trong Chuỗi bằng cách sử dụng String.prototype[@@iterator], nó trả về một giá trị của loại Biểu tượng nổi tiếng Symbol.iterator- trình lặp mặc định cho các Đối tượng giống như mảng ( Stringtrong trường hợp này).

Mã ví dụ:

const str = 'The quick red 🦊 jumped over the lazy 🐶! 太棒了!';

let iterator = str[Symbol.iterator]();
let theChar = iterator.next();

while(!theChar.done) {
  console.log(theChar.value);
  theChar = iterator.next();
}

// logs every unicode character as expected into the console.

Điều này hoạt động với các ký tự Unicode như biểu tượng cảm xúc hoặc các ký tự không phải là chữ La Mã sẽ tăng các cấu trúc cũ.

Tham khảo: Liên kết MDN với String.prototype @@ iterator .


2
Lưu ý rằng bạn có thể thực hiện việc này theo cách ngắn hơn với một for ... ofvòng lặp cũng qua chuỗi - đó là đường cú pháp để truy cập vào trình vòng lặp.
MP Aditya

6

Bây giờ bạn có thể sử dụng trong từ khóa.

    var s = 'Alien';
    for (var c in s) alert(s[c]);


Sử dụng trong thực tế là xấu và khủng khiếp khi chưa được lọc Tôi khuyên bạn nên chống lại điều này
Downgoat

4
@Downgoat vì sao? Có gì xấu về nó? Ý tôi là nếu tôi ở trong một tình huống mà tôi biết rằng 'in' được hỗ trợ bởi công cụ Javascript của tôi và mã của tôi sẽ không tìm được đường vào công cụ khác ... tại sao không sử dụng điều đó?
TKoL

@TKoL Xem cái này .
Alan

@Alan inlà một phần hợp pháp của ngôn ngữ. Sử dụng những thứ phù hợp. Bài viết của bạn cảnh báo rằng indiễn giải các khóa alpha giống như các phím số. Vì thế? Có lẽ đó là những gì bạn muốn. Cũng có thể nói rằng các phương pháp khác bỏ qua các phím alpha không chính xác . Imo, ofcó hành vi đúng. Trong mảng JS, các phần tử không có khóa alpha vẫn có các khóa: số. Trong bảng điều khiển của tôi, JS "chính xác" xử lý khóa alpha giống như các phím số:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny tại sao

5

Bạn có thể nhận được một mảng các ký tự riêng lẻ như vậy

var test = "test string",
    characters = test.split('');

và sau đó lặp bằng cách sử dụng Javascript thông thường hoặc nếu không bạn có thể lặp qua các ký tự của chuỗi bằng jQuery bằng cách

var test = "test string";

$(test.split('')).each(function (index,character) {
    alert(character);
});

5

bạn có thể chuyển đổi chuỗi này thành một mảng các ký tự bằng cách sử dụng split(), sau đó lặp qua nó.

const str = "javascript";
const strArray = str.split('');

strArray.map(s => console.log(s));


rõ ràng điều này thất bại với các ký tự unicode và biểu tượng đồ họa.
johny tại sao

4

Nếu bạn muốn thực hiện chuyển đổi trên văn bản ở cấp độ ký tự và nhận lại văn bản đã chuyển đổi ở cuối, bạn sẽ làm một cái gì đó như thế này:

var value = "alma";
var new_value = value.split("").map(function(x) { return x+"E" }).join("")

Vì vậy, các bước:

  • Chia chuỗi thành một mảng (danh sách) các ký tự
  • Ánh xạ mỗi nhân vật thông qua một functor
  • Nối các mảng kết quả của các ký tự lại với nhau thành chuỗi kết quả

0

Trong JavaScript ngày nay, bạn có thể

Array.prototype.map.call('This is my string', (c) => c+c)

Rõ ràng, c + c đại diện cho bất cứ điều gì bạn muốn làm với c.

Điều này trở lại

["TT", "hh", "ii", "ss", " ", "ii", "ss", " ", "mm", "yy", " ", "ss", "tt", "rr", "ii", "nn", "gg"]


Có thể:[...'This is my string'].map((c)=>c+c)
Alan

0

Điều này sẽ hoạt động trong các trình duyệt cũ hơn và với các ký tự UTF-16 như.

Đây phải là giải pháp tương thích nhất. Tuy nhiên, nó ít hiệu quả hơn một forvòng lặp.

Tôi đã tạo biểu thức chính quy bằng regrecu

var str = 'My String 💩 ';
var regEx = /(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g


str.replace(regEx, function (char) {
    console.log(char)
});

Hi vọng điêu nay co ich!


Bạn có ý nghĩa gì bởi "ít nước hoa"? Tôi nghĩ bạn có nghĩa là "chậm hơn" vì nó phù hợp hơn với yêu cầu và nó thực hiện tốt.
hà mã

-1

Bạn có thể truy cập các ký tự đơn với str.charAt(index)hoặc str[index]. Nhưng cách thứ hai không phải là một phần của ECMAScript để bạn tốt hơn với cách trước.


Tôi sẽ tránh xa điều đó. Thật không may, nó không hoạt động trong tất cả các phiên bản IE. Tin tôi đi Tôi đã học nó một cách khó khăn.
Xavi

3
Nó là một phần của ECMAScript, nhưng chỉ trong phiên bản thứ 5 mới phát hành, không phải thứ 3.
kangax

-1

Nếu bạn muốn tạo hiệu ứng cho từng nhân vật, bạn có thể cần phải bọc nó trong phần tử span;

var $demoText = $("#demo-text");
$demoText.html( $demoText.html().replace(/./g, "<span>$&amp;</span>").replace(/\s/g, " "));

Tôi nghĩ rằng đây là cách tốt nhất để làm điều đó, sau đó xử lý các nhịp. (ví dụ với TweenMax)

TweenMax.staggerFromTo ($ demoText.find ("span"), 0.2, {autoAlpha: 0}, {autoAlpha: 1}, 0.1);


-1

Hãy thử mã này

    function myFunction() {
    var text =(document.getElementById("htext").value); 
    var meow = " <p> <,> </p>";
    var i;


    for (i = 0; i < 9000; i++) {

        text+=text[i] ;



    }

    document.getElementById("demo2").innerHTML = text;

}
</script>
<p>Enter your text: <input type="text" id="htext"/>

    <button onclick="myFunction();">click on me</button>
</p>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.