如何使用Javascript处理每个字母?


361

我想提醒一个字符串的每个字母,但是我不确定该怎么做。

所以,如果我有:

var str = 'This is my string';

我希望能够分别警告T,h,i,s等。这仅仅是我正在研究的一个想法的开始,但是我需要知道如何分别处理每个字母。

我想使用jQuery,并考虑在测试字符串的长度后可能需要使用split函数。

有想法吗?


3
也许您正在寻找的是:从ES6开始,有for(const c of str) { ... }。下文将在更详细但并未充分支持的答案中进一步介绍更多内容。PS:@ARJUN的链接对我不起作用。
最大

Answers:


419

如果警报的顺序很重要,请使用以下命令:

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

如果警报的顺序无关紧要,请使用以下命令:

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


2
[]在IE <9中不支持使用来将字符置于特定位置
-vsync

13
如其他答案所述,您可以使用str.charAt(i)代替[]。有关为什么应使用charAt vs []的更多信息,请参见string.charAt(x)或string [x]
朱利安·索罗

12
我发现很难相信,如果没有在循环内修改字符串,那么任何现代JS编译器都会重新计算长度。在其他每种语言中,我都会很高兴在for循环的test子句中进行长度检查,假设编译器最了解并会对其进行优化。
梯队2014年

3
@Dagmar:Javascript不使用UTF-8,它使用UTF-16(或UCS-2,具体取决于浏览器)。每个字符都可以表示为UTF-8或UTF-16,但不会出现此问题。唯一有问题的是在UTF-16中需要四个字节而不是两个字节的字节。💩是在UTF-16中需要四个字节的字符。查找更多信息的关键术语是“星形平面”,“非BMP”和“代理对”。
hippietrail

1
@Dagmar:Java和Javascript都具有UTF-16(以前称为UCS-)的共同点。使用它的第三个主要平台是Windows。Unix,MacOS和Internet协议使用UTF-8。charAt在没有代理对的情况下是从UCS-2天遗留下来的,为了解决这个问题,codepointAtJavaScript中添加了一个新功能,可以正确处理我们友好的便便。我相信Java也有它。
hippietrail

240

这可能远不止于此。只想贡献另一个简单的解决方案:

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
最后一个例子可以是[...text].forEach(console.log)
Govind Rai

10
不,不能。forEach()将索引和数组作为第二和第三个参数传递。我宁愿不日志..
Goferito先生

1
请注意,散布运算符(第一个示例)和拆分调用(最后一个示例)都将创建一个新数组。这通常不会有问题,但是对于大型字符串或频繁使用而言可能会很昂贵。
Randolpho

怎么样for (let c of [...text]) { console.log(c) }
Flimm

这样,您就可以从字符串创建一个新数组。我没有看到好处。let c of text已经做好了
Goferito先生19年

73

纯JavaScript的一种可能的解决方案:

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

var x = 0和var c = str.charAt(x)可能会更好。
Rich

2
另外,str.length应该存储在变量中,这样就不必继续访问它。
伊莱·格雷

8
@EliGrey将长度放在变量中真的重要吗?您是否有基准,这比使用更少的代码行更可取?
pm_labs

@paul_sns有趣的是,似乎确实存在微小的差异,至少在Edge中(对于10000个元素数组,差异为0.7ms):jsfiddle.net/carcigenicate/v8vvjoc1/1。可能不是一个完美的测试,但它基于平均10000个测试。
Carcigenicate's

1
@paul_sns同样有趣的是,Chrome在大约2%的时间内进行了相同的测试(〜5ms与〜0.0997ms),并且两个版本给出了相同的时间,因此好像Edge没有得到优化。
Carcigenicate's

69

如何处理每个文本字母(带有基准)

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

对于

经典的,迄今为止性能最强的一种。如果您打算在性能关键的算法中使用它,或者它要求与浏览器版本具有最大的兼容性,则应使用此算法。

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

对于...的

for ... of是新的迭代器ES6。大多数现代浏览器都支持。它在外观上更具吸引力,并且不太容易出现输入错误。如果您打算在生产应用程序中使用该程序,则可能应该使用像Babel这样的编译器。

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

每次

功能方法。Airbnb批准。这样做的最大缺点是split(),它会创建一个新数组来存储字符串的每个字母。

为什么?这执行了我们不变的规则。处理返回值的纯函数比副作用更容易推论。

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

要么

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

以下是我不喜欢的内容。

为...在

与for ... of不同,您得到字母索引而不是字母。它表现很差。

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

地图

函数方法,这很好。但是,地图并不打算用于此目的。需要更改数组中的值时应使用它,不是这种情况。

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

要么

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

1
在我的机器上,经典for循环实际上是第二慢的,而for...of最快的循环(约为的三倍for)。
约翰·蒙哥马利

1
基准在哪里?什么是最快的解决方案?
poitroae

1
@johnywhy那是两年前的事,该链接已经失效了,所以我不确定您希望我如何捍卫我当时获得的结果。尽管现在建立一个新的基准测试与zurfyx的结论是一致的,但是for循环要快一些。
约翰·蒙哥马利

1
@JohnMontgomery我不希望您做任何事情。只是给将来的读者一个提示,即您的结果与答案不同。我个人想知道2020年今天的结果适用于浏览器,而直到2018年才问世。哪个链接无效?
约翰尼为什么

1
@johnywhy顶部所有实际测试的链接为我返回了404。
约翰·蒙哥马利

42

这里的大多数(如果不是全部)答案都是错误的,因为只要Unicode BMP(基本多语言平面)之外的字符串中有字符,它们就会中断。这意味着所有表情符号都将被破坏

JavaScript 对所有字符串都使用UTF- 16 Unicode。在UTF-16中,超出BMP的字符由两部分组成,称为“ 代理 ”,此处的大多数答案将单独处理此类对的每个部分,而不是将其作为单个字符。

至少从2016年开始,现代JavaScript中的一种方法是使用新的String迭代器。这是(几乎)来自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
有关在考虑代理对的情况下将字符串拆分为字符的现代解决方案,请参见:stackoverflow.com/a/42596897/527702
hippietrail

20

你可以试试这个

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

11
仍然是一个选择,但不是高性能。不要将jQuery放在任何地方。
cagatay

10

另一种解决方案...

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

3
如果你只是想炭,而不是指数,这将是更快地使用一个for..of循环for (let ch of t) { alert(ch) }
沙欣Ghiassy

10

当我需要编写短代码或单行代码时,请使用以下“ hack”:

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

这不会计算换行符,因此可以是好事或坏事。如果其中包括换行符替换:/.//[\S\s]/。其他的俏皮话可能会看到可能使用.split()有很多问题


最佳答案。考虑到的问题unicode和也可以与用.MAP功能构建体(使用)等
rofrol

关于这一点,我唯一不喜欢的事情是,当我想访问传递给forEach调用函数额外参数与传入参数时replace。如果我知道我正在使用ASCII码,我想我还有一些用例split。很好的答案!
鲁芬

该答案具有预选您将要对照的任何值的好处
Fuzzyma

1
我认为除非将u标志与标志一起使用,否则不会考虑Unicode问题g?确定,只是测试,我是对的。
hippietrail

9

新的JS允许这样做:

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

8

如果字符串包含Unicode字符,则最好使用for ... of语句,因为字节大小不同。

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

7

简短的答案:Array.from(string)将为您提供可能想要的内容,然后可以对其进行迭代或其他任何操作,因为它只是一个数组。

好的,让我们尝试使用以下字符串:abc|⚫️\n⚪️|👨‍👩‍👧‍👧

代码点是:

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

因此有些字符有一个代码点(字节),有些字符有两个或更多,并增加了换行符以进行额外的测试。

因此,测试后有两种方法:

  • 每个字节一个字节(每个代码点一个代码点)
  • 字符组(但不是整个家庭的表情符号)

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

现在,您可以使用来遍历String中包含的各个Unicode代码点String.prototype[@@iterator],这将返回众所周知的Symbol类型Symbol.iterator的值-类数组对象的默认迭代器(String在这种情况下)。

示例代码:

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.

这适用于Unicode字符(例如表情符号或非罗马字符),这些字符会破坏传统结构。

参考:MDN链接到String.prototype @@ iterator


2
请注意,您可以通过for ... of循环以及在字符串上以更短的方式执行此操作-这是用于访问迭代器的语法糖。
Aditya MP

6

您现在可以关键字中使用。

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


使用in是一种不好的做法,并且未经过滤
就很

4
@Downgoat为什么?这有什么不好?我的意思是,如果我处在这样的情况下,我的Javascript引擎支持“ in”,并且我的代码无法进入另一个引擎...为什么不使用它?
TKoL

@TKoL看到这个
艾伦

@Alan in是该语言的合法组成部分。适当使用东西。您的文章警告说,in解释字母键与数字键相同。所以?也许这就是您想要的。也可以说其他方法错误地忽略了字母键。Imo,of行为正确。在JS数组中,没有字母键的元素仍然具有键:数字键。在我的控制台中,JS“正确地”将字母键与数字键相同:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny为什么

5

您可以像这样获得单个字符的数组

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

然后使用常规Javascript循环,否则您可以使用jQuery通过以下方式迭代字符串的字符:

var test = "test string";

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


4

如果要在字符级别上对文本进行转换,并在最后返回转换后的文本,则可以执行以下操作:

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

因此,步骤如下:

  • 将字符串拆分为字符数组(列表)
  • 通过函子映射每个角色
  • 将生成的字符数组连接到生成的字符串中

0

在当今的JavaScript中,您可以

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

显然,c + c表示您想要对c做的任何事情。

这返回

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


可能:[...'This is my string'].map((c)=>c+c)
艾伦

0

这应在较旧的浏览器中并使用诸如U之类的UTF-16字符即可。

这应该是最兼容的解决方案。但是,它的性能不如for循环。

我使用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)
});

希望这可以帮助!


您所说的“更少的表现”是什么意思?我认为您的意思是“较慢”,因为它更符合要求并且运行良好。
hippietrail

-1

您可以使用或来访问单个字符。但是后一种方法不是ECMAScript的一部分,因此您最好选择前一种。str.charAt(index)str[index]


我会远离那个。不幸的是,这不适用于所有版本的IE。相信我。我很难学。
哈维

3
它是ECMAScript的一部分,但仅适用于新发行的第5版,而不是第3版。
kangax

-1

如果要为每个角色设置动画,则可能需要将其包装在span元素中;

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

我认为这是最好的方法,然后处理跨度。(例如,使用TweenMax)

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


-1

试试这个代码

    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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.