String.prototype.charAt()

Сводка

Метод charAt() возвращает указанный символ из строки.

Синтаксис

str.charAt(index)

Параметры

index
Целое число от 0 до длины строки минус 1.

Описание

Символы в строке идут слева направо. Индекс первого символа равен 0, а последнего символа в строке stringName равен stringName.length - 1. Если предоставленный вами параметр index выходит за пределы этого диапазона, JavaScript вернёт пустую строку.

Примеры

Пример: отображение символов из различных позиций строки

Следующий пример показывает символы в различных позициях в строке "Дивный новый мир":

var anyString = 'Дивный новый мир';

console.log("Символ по индексу 0   равен '" + anyString.charAt(0)   + "'");
console.log("Символ по индексу 1   равен '" + anyString.charAt(1)   + "'");
console.log("Символ по индексу 2   равен '" + anyString.charAt(2)   + "'");
console.log("Символ по индексу 3   равен '" + anyString.charAt(3)   + "'");
console.log("Символ по индексу 4   равен '" + anyString.charAt(4)   + "'");
console.log("Символ по индексу 5   равен '" + anyString.charAt(5)   + "'");
console.log("Символ по индексу 999 равен '" + anyString.charAt(999) + "'");

Этот код отобразит следующее:

Символ по индексу 0   равен 'Д'
Символ по индексу 1   равен 'и'
Символ по индексу 2   равен 'в'
Символ по индексу 3   равен 'н'
Символ по индексу 4   равен 'ы'
Символ по индексу 5   равен 'й'
Символ по индексу 999 равен ''

Пример: получение целых символов

Следующий пример показывает, как обойти строку в цикле, каждый раз гарантированно получая целый символ, даже если строка содержит символы, не помещающиеся на Базовую многоязыковую плоскость (БМП).

var str = 'A \uD87E\uDC04 Z'; // Также можно использовать не-БМП символы напрямую
for (var i = 0, chr; i < str.length; i++) {
  if ((chr = getWholeChar(str, i)) === false) {
    continue;
  }
  // Поместите эти строки в самое начало каждого цикла, передавая в функцию строку
  // и текущую итерацию; возвращаемая переменная будут представлять
  // отдельный символ

  console.log(chr);
}

function getWholeChar(str, i) {
  var code = str.charCodeAt(i);

  if (isNaN(code)) {
    return ''; // Позиция не найдена
  }
  if (code < 0xD800 || code > 0xDFFF) {
    return str.charAt(i);
  }

  // Старшая часть суррогатной пары (последнее число можно изменить на 0xDB7F,
  // чтобы трактовать старшую часть суррогатной пары в частной плоскости как
  // одиночный символ)
  if (0xD800 <= code && code <= 0xDBFF) {
    if (str.length <= (i + 1)) {
      throw 'Старшая часть суррогатной пары без следующей младшей';
    }
    var next = str.charCodeAt(i + 1);
      if (0xDC00 > next || next > 0xDFFF) {
        throw 'Старшая часть суррогатной пары без следующей младшей';
      }
      return str.charAt(i) + str.charAt(i + 1);
  }
  // Младшая часть суррогатной пары (0xDC00 <= code && code <= 0xDFFF)
  if (i === 0) {
    throw 'Младшая часть суррогатной пары без предшествующей старшей';
  }
  var prev = str.charCodeAt(i - 1);

  // (последнее число можно изменить на 0xDB7F, чтобы трактовать старшую
  // часть суррогатной пары в частной плоскости как одиночный символ)
  if (0xD800 > prev || prev > 0xDBFF) {
    throw 'Младшая часть суррогатной пары без предшествующей старшей';
  }
  // Теперь мы можем пропустить младшую часть суррогатной пары,
  // которую мы уже обработали
  return false;
}

В среде, поддерживающей JavaScript 1.7+ (например, в Firefox), который позволяет деструктуризующее присваивание, можно использовать более лаконичную и более гибкую альтернативу в том смысле, что она автоматически увеличивает счётчик (если символ гарантированно является суррогатной парой).

var str = 'A\uD87E\uDC04Z'; // Также можно использовать не-БМП символы напрямую
for (var i = 0, chr; i < str.length; i++) {
  [chr, i] = getWholeCharAndI(str, i);
  // Поместите эту строку в самое начало каждого цикла, передавая в функцию строку
  // и текущую итерацию; возвращаемый массив будет содержать отдельный символ и
  // новое значение счётчика цикла 'i' (изменится только при встрече суррогатной пары)

  console.log(chr);
}

function getWholeCharAndI(str, i) {
  var code = str.charCodeAt(i);

  if (isNaN(code)) {
    return ''; // Позиция не найдена
  }
  if (code < 0xD800 || code > 0xDFFF) {
    return [str.charAt(i), i]; // Обычный символ, оставляем переменную 'i' неизменной
  }

  // Старшая часть суррогатной пары (последнее число можно изменить на 0xDB7F,
  // чтобы трактовать старшую часть суррогатной пары в частной плоскости как
  // одиночный символ)
  if (0xD800 <= code && code <= 0xDBFF) {
    if (str.length <= (i + 1)) {
      throw 'Старшая часть суррогатной пары без следующей младшей';
    }
    var next = str.charCodeAt(i + 1);
      if (0xDC00 > next || next > 0xDFFF) {
        throw 'Старшая часть суррогатной пары без следующей младшей';
      }
      return [str.charAt(i) + str.charAt(i + 1), i + 1];
  }
  // Младшая часть суррогатной пары (0xDC00 <= code && code <= 0xDFFF)
  if (i === 0) {
    throw 'Младшая часть суррогатной пары без предшествующей старшей';
  }
  var prev = str.charCodeAt(i - 1);

  // (последнее число можно изменить на 0xDB7F, чтобы трактовать старшую
  // часть суррогатной пары в частной плоскости как одиночный символ)
  if (0xD800 > prev || prev > 0xDBFF) {
    throw 'Младшая часть суррогатной пары без предшествующей старшей';
  }
  // Возвращаем следующий символ (и увеличиваем счётчик)
  return [str.charAt(i + 1), i + 1];
}

Пример: добавление к методу charAt() поддержки символов не в Базовой многоязыковой плоскости (БМП)

В то время как пример выше может быть более полезен тем, кто хочет поддерживать символы не в плоскости БМП (поскольку он не требует от вызывающей стороны знания о том, где может встретиться символ из не-БМП), в случае, если кто-то желает выбирать символы по индексу и трактовать суррогатную пару внутри строки как один символ, он может использовать следующий код:

function fixedCharAt(str, idx) {
  var ret = '';
  str += '';
  var end = str.length;

  var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
  while ((surrogatePairs.exec(str)) != null) {
    var li = surrogatePairs.lastIndex;
    if (li - 2 < idx) {
      idx++;
    } else {
      break;
    }
  }

  if (idx >= end || idx < 0) {
    return '';
  }

  ret += str.charAt(idx);

  if (/[\uD800-\uDBFF]/.test(ret) && /[\uDC00-\uDFFF]/.test(str.charAt(idx + 1))) {
    // Перешагиваем через один, поскольку один «символ» является частью суррогатной пары
    ret += str.charAt(idx + 1);
  }
  return ret;
}

Спецификации

Спецификация Статус Комментарии
ECMAScript 1-е издание. Стандарт Изначальное определение.
ECMAScript 5.1 (ECMA-262)
Определение 'String.prototype.charAt' в этой спецификации.
Стандарт  
ECMAScript 2015 (6th Edition, ECMA-262)
Определение 'String.prototype.charAt' в этой спецификации.
Стандарт  

Совместимость с браузерами

Возможность Chrome Firefox (Gecko) Internet Explorer Opera Safari
Базовая поддержка (Да) (Да) (Да) (Да) (Да)
Возможность Android Chrome для Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Базовая поддержка (Да) (Да) (Да) (Да) (Да) (Да)

Смотрите также

Метки документа и участники

 Внесли вклад в эту страницу: Mingun
 Обновлялась последний раз: Mingun,