573

I would like to alert each letter of a string, but I am unsure how to do this.

So, if I have:

var str = 'This is my string';

I would like to be able to separately alert T, h, i, s, etc. This is just the beginning of an idea that I am working on, but I need to know how to process each letter separately.

I was thinking I might need to use the split function after testing what the length of the string is.

How can I do this?

Aryan Beezadhur
  • 4,503
  • 4
  • 21
  • 42
Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412
  • 10
    Maybe you were looking for this: as of ES6, there is `for(const c of str) { ... }`. More of that further below in a quite detailed but not sufficiently upvoted answer. PS: @ARJUN's link doesn't work for me. – Max Jan 27 '19 at 16:03

24 Answers24

624

If the order of alerts matters, use this:

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

Or this: (see also this answer)

 for (let i = 0; i < str.length; i++) {
   alert(str[i]);
 }

If the order of alerts doesn't matter, use this:

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

Or this: (see also this answer)

let i = str.length;
while (i--) {
  alert(str[i]);
}

var str = 'This is my string';

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

function dontmatter() {
  let i = str.length;
  while (i--) {
    alert(str.charAt(i));
  }
}
<p>If the order of alerts matters, use <a href="#" onclick="matters()">this</a>.</p>

<p>If the order of alerts doesn't matter, use <a href="#" onclick="dontmatter()">this</a>.</p>
UselesssCat
  • 2,248
  • 4
  • 20
  • 35
Eli Grey
  • 35,104
  • 14
  • 75
  • 93
  • 4
    using the `[]` to get the char in a specific position isn't supported in IE < 9 – vsync Jan 09 '14 at 13:33
  • 19
    as covered in the other answer, you could use str.charAt(i) in place of the []'s. for more on why you should use charAt vs [], see [string.charAt(x) or string\[x\]](http://stackoverflow.com/questions/5943726/string-charatx-or-stringx) – julian soro May 29 '14 at 20:28
  • 18
    I find it hard to believe any modern JS compiler would re-calculate the length if the string hasn't been modified inside the loop. In every other language I'd happily do the length check in the test clause of the for loop, assuming the compiler knows best and would optimise it accordingly. – Echelon Dec 16 '14 at 11:43
  • 3
    @Dagmar: Javascript does not use UTF-8, it uses UTF-16 (or UCS-2, depending on the browser). Every single character can be represented as either UTF-8 or UTF-16 but not have this problem. The only ones that have the problem are the ones that require four bytes in UTF-16 rather than two bytes. is a character that requires four bytes in UTF-16. Key terms to look up for more info are "astral plane", "non-BMP", and "surrogate pair". – hippietrail Feb 27 '18 at 03:28
  • @hippietrail I'm a Java not Javascript dev so thanks for your reply. However I'd like to point out that it really depends on your container - like you said it depends on the browser (and as far as I know I can't specify the encoding I'd like to use). I was testing with Google App Scripts and `charAt` definitely did not work for characters like the pile of poop (which can be displayed in UTF-8 and UTF-16 as 4 bytes). https://www.fileformat.info/info/unicode/char/1f4a9/index.htm – Dagmar Feb 28 '18 at 05:13
  • 1
    @Dagmar: Java and Javascript both have UTF-16 (formerly UCS-) in common. The third major platform that uses it is Windows. Unix, MacOS, and internet protocols use UTF-8. `charAt` is left over from the UCS-2 days when there were no surrogate pairs and to address the problem a new function, `codepointAt` was added to JavaScript that handles our friendly pile of poo correctly. I believe Java also has it. – hippietrail Feb 28 '18 at 09:13
  • The codePointAt method gives you character codes instead of actual characters, though. Is there a method like charAt, but which correctly returns a poop emoji as a character instead of a code? – Andrew Koster Feb 12 '19 at 23:29
  • @AndrewKoster: Sometimes I too confuse two of this group of functions. Here is the whole set of them: [`charAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt), [`charCodeAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt), [`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt), [`fromCharCode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode), ... – hippietrail Dec 06 '19 at 15:13
  • @AndrewKoster: ... and [`fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) – hippietrail Dec 06 '19 at 15:14
  • For me the first solution was more than 50% faster when I benchmarked it on Firefox. – Rutger Willems Apr 05 '20 at 09:07
  • 1
    @RutgerWillems Faster than what? – johny why May 06 '20 at 23:36
  • Maybe not as good as others, but my 2 cents are => `string.split('').forEach(letter => ...);` – Eugene Dec 20 '20 at 00:24
  • I personally like 2nd while solution – Ivandez Feb 16 '22 at 15:21
441

It's probably more than solved. Just want to contribute with another simple solution:

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);
});
Mr. Goferito
  • 6,391
  • 4
  • 26
  • 27
  • 7
    the last example can simply be `[...text].forEach(console.log)` – Govind Rai Jul 31 '18 at 18:33
  • 21
    Nope, it can't. `forEach()` passes the index and the array as second and third argument. I would rather not log that.. – Mr. Goferito Aug 01 '18 at 20:39
  • 2
    Note that both the spread operator (first example) and the split call (last example) will create a new array. This won't usually be a problem, but could be costly for large strings or frequent uses. – Randolpho Feb 21 '19 at 16:02
  • 2
    What about `for (let c of [...text]) { console.log(c) }` – Flimm Nov 04 '19 at 15:05
  • With that you create a new array from the string. I don't see the benefit. `let c of text` already does the job. – Mr. Goferito Nov 05 '19 at 16:15
  • What does the `...` stand for? I tried without and I see the difference but, why? – Revolucion for Monica Nov 06 '19 at 15:24
  • @IggyPass It's the spread operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – Mr. Goferito Nov 07 '19 at 15:26
  • TypeScript can be funny about `[...text]` trying to treat a string as an iterator, alternatively use `text.split("")`. – Greg K Nov 08 '19 at 17:03
  • 6
    Of these, only the first two will iterate through the characters of the string. The rest iterate though the UTF-16 code units. For example try `text = "\ud835\udcaf\ud835\udcae\ud835\udca9"` This string has 3 unicode characters in it, but 6 code-units. – Theodore Norvell Aug 27 '20 at 15:09
  • More specifically the first two iterate through the unicode code points, not characters. Multiple unicode codepoints can make up a character. – Cameron Martin Feb 07 '21 at 18:16
  • @Flimm no need to encapsulate the console.log: `for (let c of [...str]) console.log(c)` will work – Chris Perry Apr 04 '21 at 00:37
118

How to process each letter of text (with benchmarks)

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

for

Classic and by far the one with the most performance. You should go with this one if you are planning to use it in a performance critical algorithm, or that it requires the maximum compatibility with browser versions.

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

for...of

for...of is the new ES6 for iterator. Supported by most modern browsers. It is visually more appealing and is less prone to typing mistakes. If you are going for this one in a production application, you should be probably using a transpiler like Babel.

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

forEach

Functional approach. Airbnb approved. The biggest downside of doing it this way is the split(), that creates a new array to store each individual letter of the string.

Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.

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

or

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

The following are the ones I dislike.

for...in

Unlike for...of, you get the letter index instead of the letter. It performs pretty badly.

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

map

Function approach, which is good. However, map isn't meant to be used for that. It should be used when needing to change the values inside an array, which is not the case.

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

or

let result = '';
str.split('').map(function(letter) {
  result += letter;
});
hippietrail
  • 15,848
  • 18
  • 99
  • 158
zurfyx
  • 31,043
  • 20
  • 111
  • 145
  • 1
    On my machine the classic `for` loop was actually the second slowest, while `for...of` was the fastest (about three times as fast as `for`). – John Montgomery Jun 01 '18 at 23:28
  • 7
    Where is the benchmark? What's the fastest solution? – poitroae Dec 03 '19 at 09:21
  • @JohnMontgomery Your results seem contrary to zurfyx assertion that the classic loop is fastest. – johny why May 07 '20 at 05:09
  • my understanding is the split method will fail on unicode or graphic symbols. – johny why May 07 '20 at 05:10
  • 1
    @johnywhy That was two years ago and the link is dead so I'm not sure how you expect me to defend the result I got back then. Setting up a new benchmark now agrees with zurfyx's conclusion though, with the `for` loop being slightly faster. – John Montgomery May 11 '20 at 18:32
  • 1
    @JohnMontgomery I don't expect you to do anything. Just a note to future readers that your results are different than the answer. I personally would like to know which results apply to browsers today 2020, altho' 2018 wasn't that long ago. Which link is dead? – johny why May 11 '20 at 20:31
  • 1
    @johnywhy The link at the top with all the actual tests is returning a 404 for me. – John Montgomery May 11 '20 at 21:40
77

One possible solution in pure javascript:

for (var x = 0; x < str.length; x++)
{
    var c = str.charAt(x);
    alert(c);
}
miku
  • 181,842
  • 47
  • 306
  • 310
  • It would probably be better with var x = 0 and var c = str.charAt(x). – Rich Dec 27 '09 at 18:09
  • 3
    Also, str.length should be stored in a variable so it doesn't have to keep being accessed. – Eli Grey Dec 27 '09 at 21:48
  • 8
    @EliGrey Is it really that important to put length in a variable? Do you have benchmarks when this would be preferable over having fewer lines of code? – pm_labs Apr 16 '13 at 02:22
  • @paul_sns Interestingly, there does seem to be a *minor* difference, at least in Edge (0.7ms difference for a 10000 element array): https://jsfiddle.net/carcigenicate/v8vvjoc1/1/. Probably not a perfect test, but it's based of an average of 10000 tests. – Carcigenicate Mar 06 '16 at 20:09
  • 1
    @paul_sns Also interestingly, Chrome did the same test in around 2% of the time (~5ms vs ~0.0997ms), and both versions gave the same time, so it looks like Edge isn't optimized. – Carcigenicate Mar 06 '16 at 20:18
  • @Carcigenicate Chrome uses more processor time, so it isn't a fair test, unless you're using an OS with perfect, static throttling. And such an OS isn't very useful for multitasking, as a program that grabs loads of PIDs will get lots of time (something Chrome *also* does!). – wizzwizz4 Jul 18 '16 at 18:37
  • @Carcigenicate, I think your test is mostly measuring the performance of Array.push instead of Array.length. – cagatay Jan 31 '17 at 06:53
  • 1
    for (var x = 0, c=''; c = "".charAt(x); x++) { console.log(c); } – James May 03 '20 at 16:40
  • "One possible solution in pure javascript". Oh I'm sure there's a jQuery plugin to do this easily, why bother looping?? – code Feb 15 '22 at 05:39
58

Most if not all of the answers here are wrong because they will break whenever there is a character in the string outside the Unicode BMP (Basic Multilingual Plane). That means all Emoji will be broken.

JavaScript uses UTF-16 Unicode for all strings. In UTF-16, characters beyond the BMP are made out of two parts, called a "Surrogate Pair" and most of the answers here will process each part of such pairs individually instead of as a single character.

One way in modern JavaScript since at least 2016 is to use the new String iterator. Here's the example (almost) straight out of 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"
hippietrail
  • 15,848
  • 18
  • 99
  • 158
  • 5
    For a modern solution to splitting a string into characters while taking into account surrogate pairs, see: https://stackoverflow.com/a/42596897/527702 – hippietrail Jul 05 '17 at 09:24
19

You can try this

var arrValues = 'This is my string'.split('');
// Loop over each value in the array.
$.each(arrValues, function (intIndex, objValue) {
    alert(objValue);
})
royhowie
  • 11,075
  • 14
  • 50
  • 67
Adriaan Stander
  • 162,879
  • 31
  • 289
  • 284
15

New JS allows this:

const str = 'This is my string';
Array.from(str).forEach(alert);
papajson
  • 151
  • 1
  • 2
  • 1
    Best answer! I intuitively tried it and it worked, wanted to post it, then discovered that I'm too late ) – Fancy John Dec 15 '21 at 23:13
14

If you want to do a transformation on the text on a character level, and get the transformed text back at the end, you would do something like this:

var value = "alma";
var new_value = [...value].map((x) => x+"E").join("")

So the steps:

  • Split the string into an array (list) of characters
  • Map each character via a functor
  • Join the resulting array of chars together into the resulting string

NOTE: If you need performance, there are probably better, more optimized solutions for this. I posted this one as a clean codestyle approach.

Vajk Hermecz
  • 5,413
  • 2
  • 34
  • 25
10

One more solution...

var strg= 'This is my string';
for(indx in strg){
  alert(strg[indx]);
}
Pamsix
  • 129
  • 1
  • 3
10

It is better to use the for...of statement, if the string contains unicode characters, because of the different byte size.

for(var c of "tree 木") { console.log(c); }
//"A".length === 3
Martin Wantke
  • 4,287
  • 33
  • 21
10

short answer: Array.from(string) will give you what you probably want and then you can iterate on it or whatever since it's just an array.

ok let's try it with this string: abc|⚫️\n⚪️|‍‍‍.

codepoints are:

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

so some characters have one codepoint (byte) and some have two or more, and a newline added for extra testing.

so after testing there are two ways:

  • byte per byte (codepoint per codepoint)
  • character groups (but not the whole family emoji)

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
});
localhostdotdev
  • 1,795
  • 16
  • 21
9

When I need to write short code or a one-liner, I use this "hack":

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

This won't count newlines so that can be a good thing or a bad thing. If you which to include newlines, replace: /./ with /[\S\s]/. The other one-liners you may see probably use .split() which has many problems

Downgoat
  • 13,771
  • 5
  • 46
  • 69
  • best answer. Takes into account problems with unicode and also can be used with functional constructs with .map() etc. – rofrol Aug 05 '15 at 21:28
  • Only thing I don't like about this one is when I want access to the [extra params passed to the `forEach` call's function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Parameters) vs the [params sent in `replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter). If I know I'm ASCIIing, I think I still have some use cases for `split`. Great answer, though! – ruffin Feb 22 '16 at 17:32
  • This answer has the bonus with preselecting the values you would check against anyway – Fuzzyma Apr 09 '17 at 17:21
  • 2
    I thought this wouldn't take into account the Unicode problems unless it had the `u` flag along with the `g` flag? OK just tested and I was right. – hippietrail Jul 16 '17 at 15:51
9

You can now use in keyword.

    var s = 'Alien';
    for (var c in s) alert(s[c]);
John Hascall
  • 9,176
  • 6
  • 48
  • 72
mih0vil
  • 148
  • 1
  • 5
  • Using in is bad practice and horrible when unfiltered I strongly advise against this – Downgoat Feb 22 '16 at 22:58
  • 5
    @Downgoat why? What's bad about it? I mean if I'm in a situation where I know that 'in' is supported by my Javascript engine, and that my code won't find its way into another engine...why not use that? – TKoL Jun 08 '16 at 12:42
  • @TKoL See [this](https://thecodebarbarian.com/for-vs-for-each-vs-for-in-vs-for-of-in-javascript#non-numeric-properties). – Alan Mar 12 '20 at 14:45
  • 1
    @Alan `in` is a legitimate part of the language. Use things appropriately. Your article cautions that `in` interprets alpha keys same as numeric keys. So? Maybe that's what you want. It could also be said that other methods *incorrectly* ignore alpha keys. Imo, `of` has correct behavior. In JS arrays, elements without alpha keys still have keys: numeric ones. In my console, JS "correctly" treats the alpha key same as the numeric keys: `>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2` – johny why May 07 '20 at 01:20
  • There is nothing wrong about the usage of `in` if you know what data formats you have and in this case we know exactly that we have a string as an array. @johnywhy I totally agree with you. – Christos Lytras Jun 25 '20 at 16:58
8

You can now iterate over individual Unicode code points contained in a String by using String.prototype[@@iterator], which returns a value of well known Symbol type Symbol.iterator - the default iterator for array-like Objects (String in this case).

Example code:

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.

This works with Unicode characters such as emoji or non-roman characters that would trip up legacy constructs.

Reference: MDN Link to String.prototype@@iterator.

Aditya M P
  • 5,127
  • 7
  • 41
  • 72
  • 2
    Note that you can do this in a shorter manner with a `for ... of` loop as well over the string - that is syntax sugar for accessing the iterator. – Aditya M P Jul 16 '19 at 09:03
8

You can simply iterate it as in an array:

for(var i in txt){
    console.log(txt[i]);
}
6

In ES6 / ES2015, you can iterate over an string with iterators,as you can see in

Symbol.iterator MDN

var str = 'Hello';
var it = str[Symbol.iterator]();

for (let v of it) {
  console.log(v)
 }
 
//  "H"
//  "e"
//  "l"
//  "l"
//  "o"

It is a declarative style. What is the advantage? You do not have to concern about how to access each element of the string.

5

// There are multiple ways but I find this easiest.

let str = 'This is my string';
for(let character of str) 
  console.log(character)
4

You can get an array of the individual characters like so

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

and then loop using regular Javascript, or else you can iterate over the string's characters using jQuery by

var test = "test string";

$(test.split('')).each(function (index,character) {
    alert(character);
});
Rich
  • 3,095
  • 17
  • 17
3

you can convert this string into an array of chars using split(), then iterate through it.

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

strArray.map(s => console.log(s));
Muhammed Moussa
  • 4,589
  • 33
  • 27
0

In today's JavaScript you can

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

Obviously, c+c represents whatever you want to do with c.

This returns

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

Pum Walters
  • 339
  • 1
  • 3
  • 11
0

This should work in older browsers and with UTF-16 characters like .

This should be the most compatible solution. However, it is less performant than a for loop would be.

I generated the regular expression using regexpu

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)
});

Hope this helps!

Ben Gubler
  • 1,393
  • 3
  • 18
  • 32
  • What do you mean by "less perfomant"? I think you mean "slower" as it is more conformant to the requirement and it performs well. – hippietrail May 20 '20 at 04:00
-1

If you want to animate each character you might need to wrap it in span element;

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

I think this is the best way to do it, then process the spans. ( for example with TweenMax)

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

Chris Panayotoff
  • 1,744
  • 21
  • 24
-1

You can access single characters with str.charAt(index) or str[index]. But the latter way is not part of ECMAScript so you better go with the former one.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • I'd stay away from that. Unfortunately that doesn't work in all versions of IE. Trust me. I learned it the hard way. – Xavi Dec 27 '09 at 17:33
  • 3
    It is part of ECMAScript, but only in newly-released 5th edition, not 3rd. – kangax Dec 27 '09 at 17:38
-1

Try this code

    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>
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
meow
  • 1