Как я могу обработать каждую букву текста, используя Javascript?

363

Я хотел бы предупредить каждую отдельную букву строки, но я не уверен, как это сделать.

Итак, если у меня есть:

var str = 'This is my string';

Я хотел бы иметь возможность отдельно предупреждать T, h, i, s и т. Д. Это только начало идеи, над которой я работаю, но мне нужно знать, как обрабатывать каждое письмо отдельно.

Я хочу использовать jQuery и подумал, что мне может понадобиться использовать функцию split после проверки длины строки.

Идеи?

Ник Хаббард
источник
3
Может быть, вы искали это: с ES6, есть for(const c of str) { ... }. Более подробно об этом ниже в довольно подробном, но недостаточно голосуемом ответе. PS: ссылка @ ARJUN не работает для меня.
Макс

Ответы:

421

Если порядок оповещений имеет значение, используйте это:

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

Если порядок оповещений не имеет значения, используйте это:

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

Эли Грей
источник
2
использование []IE для получения символа в определенной позиции не поддерживается в IE <9
vsync
13
как показано в другом ответе, вы можете использовать str.charAt (i) вместо []. Подробнее о том, почему вы должны использовать charAt vs [], смотрите string.charAt (x) или string [x]
Джулиан Соро
12
Мне трудно поверить, что любой современный JS-компилятор пересчитает длину, если строка не была изменена внутри цикла. На любом другом языке я бы с удовольствием выполнил проверку длины в предложении test цикла for, предполагая, что компилятор знает лучше и оптимизирует его соответствующим образом.
Эшелон
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 и Интернет используют UTF-8. charAtосталось от дней UCS-2, когда не было суррогатных пар, и для решения проблемы codepointAtбыла добавлена новая функция в JavaScript, которая корректно обрабатывает нашу дружественную кучу пу. Я верю, что у 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)
Говинд Рай
10
Нет, не может. forEach()передает индекс и массив как второй и третий аргумент. Я бы предпочел не регистрировать это ..
Мистер Гоферито
1
Обратите внимание, что и оператор распространения (первый пример), и вызов split (последний пример) создадут новый массив. Это обычно не будет проблемой, но может быть дорогостоящим для больших строк или частого использования.
Рандольфо
Как насчетfor (let c of [...text]) { console.log(c) }
Flimm
С этим вы создаете новый массив из строки. Я не вижу выгоды. let c of textуже делает работу
г-н Гоферито
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).
Рич
2
Кроме того, str.length следует хранить в переменной, чтобы к нему не нужно было постоянно обращаться.
Эли Грей
8
@EliGrey Неужели так важно указывать длину в переменной? У вас есть тесты, когда это было бы предпочтительнее, чем иметь меньше строк кода?
pm_labs
@paul_sns Интересно, что, кажется, есть небольшая разница, по крайней мере, в Edge (разница 0,7 мс для массива элементов 10000): jsfiddle.net/carcigenicate/v8vvjoc1/1 . Вероятно, не идеальный тест, но он основан на среднем 10000 тестов.
Carcigenicate
1
@paul_sns Также интересно, что Chrome проводил один и тот же тест примерно в 2% случаев (~ 5 мс против ~ 0,0997 мс), и обе версии дали одинаковое время, так что похоже, что Edge не оптимизирован.
Carcigenicate
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;
});

Вот те, которые мне не нравятся.

для ... в

В отличие от ... вы получаете буквенный индекс вместо буквы. Это работает довольно плохо.

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;
});
zurfyx
источник
1
На моей машине классический forцикл фактически был вторым самым медленным, хотя for...ofбыл самым быстрым (примерно в три раза быстрее for).
Джон Монтгомери
1
Где эталон? Какое самое быстрое решение?
poitroae
1
@johnywhy Это было два года назад, и ссылка мертва, поэтому я не уверен, как вы ожидаете, что я буду защищать результат, который я получил тогда. Настройка нового бенчмарка теперь согласуется с выводом zurfyx, поскольку forцикл немного быстрее.
Джон Монтгомери
1
@JohnMontgomery Я не ожидаю, что ты что-то сделаешь. Просто заметка будущим читателям, что ваши результаты отличаются от ответа. Я лично хотел бы знать, какие результаты применимы к браузерам сегодня 2020, хотя 2018 год был не так давно. Какая ссылка мертва?
Джонни, почему
1
@johnywhy Ссылка вверху со всеми фактическими тестами возвращает 404 для меня.
Джон Монтгомери
42

Большинство, если не все ответы здесь неправильны, потому что они ломаются всякий раз, когда в строке за пределами Unicode BMP (Basic Multilingual Plane) есть символ . Это означает, что все эмодзи будут сломаны .

JavaScript использует UTF- 16 Unicode для всех строк. В UTF-16 символы за пределами BMP состоят из двух частей, называемых « суррогатная пара », и большинство ответов здесь будут обрабатывать каждую часть таких пар отдельно, а не как один символ.

Одним из способов в современном JavaScript, начиная с 2016 года, является использование нового итератора 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"

hippietrail
источник
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]);
}
Pamsix
источник
3
Если вам нужен только символ, а не индекс, вам будет for..offor (let ch of t) { alert(ch) }
удобнее
10

Когда мне нужно написать короткий код или однострочник, я использую этот «хак»:

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

Это не будет считать переводы строк, так что это может быть хорошо или плохо. Если вы хотите включить новые строки, замените: /./на /[\S\s]/. Вероятно, вы можете использовать другие однострочники, у .split()которых много проблем

Downgoat
источник
лучший ответ. Принимает во внимание проблемы с Unicode, а также может использоваться с функциональными конструкциями с .map () и т. Д.
rofrol
Единственное, что мне не нравится в этом, это когда я хочу получить доступ к дополнительным параметрам, передаваемым в forEachфункцию вызова, по сравнению с отправленными параметрамиreplace . Если я знаю, что я ASCIIing, я думаю, у меня все еще есть некоторые варианты использования для split. Отличный ответ, хотя!
ruffin
Этот ответ имеет бонус с предварительным выбором значений, с которыми вы все равно будете проверять
Fuzzyma
1
Я думал, что это не будет принимать во внимание проблемы Unicode, если у него не было uфлага вместе с gфлагом? ОК, только что проверил, и я был прав.
hippietrail
9

Новый JS позволяет это:

const str = 'This is my string';
Array.from(str).forEach(alert);
papajson
источник
8

Из-за разного размера байта лучше использовать оператор 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
});

localhostdotdev
источник
7

Теперь вы можете перебирать отдельные кодовые точки 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.

Это работает с символами Юникода, такими как смайлики или нелатинские символы, которые могут запутать устаревшие конструкции.

Ссылка: MDN Ссылка на String.prototype @@ iterator .

Адитья М.П.
источник
2
Обратите внимание, что вы можете сделать это более коротким способом с помощью for ... ofцикла и над строкой - это синтаксический сахар для доступа к итератору.
депутат Адитья
6

Теперь вы можете использовать в ключевом слове.

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

mih0vil
источник
Использование в это плохая практика и ужасно, когда нефильтрованный, я настоятельно советую против этого
Downgoat
4
@ Downgoat почему? Что плохого в этом? Я имею в виду, если я нахожусь в ситуации, когда я знаю, что «in» поддерживается моим движком Javascript, и что мой код не попадет в другой движок… почему бы не использовать это?
TKoL
@TKoL Посмотри на это .
Алан
@ Алан inявляется законной частью языка. Используйте вещи соответствующим образом. Ваша статья предупреждает, что inбуквенные клавиши интерпретируются так же, как цифровые клавиши. Так? Может быть, это то, что вы хотите. Можно также сказать, что другие методы неправильно игнорируют альфа-ключи. Имо, ofимеет правильное поведение. В массивах JS элементы без буквенных ключей все еще имеют ключи: числовые. В моей консоли JS "правильно" обрабатывает альфа-клавишу так же, как и цифровые клавиши:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny Why
5

Вы можете получить массив отдельных символов, как так

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

а затем цикл с использованием обычного Javascript, иначе вы можете перебирать символы строки, используя jQuery:

var test = "test string";

$(test.split('')).each(function (index,character) {
    alert(character);
});
Богатые
источник
5

Вы можете преобразовать эту строку в массив символов с помощью split(), а затем выполнить итерацию по ней.

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

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

Мухаммед Мусса
источник
по-видимому, это не работает с символами Юникода и графическими символами.
Джонни, почему
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

Это должно работать в старых браузерах и с символами 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

Вы можете получить доступ к отдельным символам с помощью str.charAt(index)или str[index]. Но последний путь не является частью ECMAScript, поэтому вам лучше пойти с первым.

гумбо
источник
Я бы держался подальше от этого. К сожалению, это не работает во всех версиях IE. Доверьтесь мне. Я научился этому нелегко.
Хави
3
Он является частью ECMAScript, но только в недавно выпущенном пятом издании, а не в третьем.
Кангакс
-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>
мяу
источник