String.prototype.charAt()

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Сводка

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

Синтаксис

str.charAt(index)

Параметры

index

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

Описание

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

Примеры

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

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

js
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) + "'");

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

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

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

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

js
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), который позволяет деструктурирующее присваивание, можно использовать более лаконичную и более гибкую альтернативу в том смысле, что она автоматически увеличивает счётчик (если символ гарантированно является суррогатной парой).

js
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() поддержки символов не в Базовой многоязыковой плоскости (БМП)

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

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

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

Specification
ECMAScript Language Specification
# sec-string.prototype.charat

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

BCD tables only load in the browser

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