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' в этой спецификации.
Стандарт  

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

BCD tables only load in the browser

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