string.charAt

charAt() method๋Š” ํŠน์ • ์ธ๋ฑ์Šค์— ์œ„์น˜ํ•œ ๋ฌธ์ž์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ํ•˜๋‚˜์˜ UTF-16 ์ฝ”๋“œ๋กœ ๊ตฌ์„ฑ๋œ ์ƒˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

const title = "The Phantom of The Opera - FULL STAGE SHOW";

const index = 4;

console.log(title.charAt(index)); // expected output: P

Syntax

character = str.charAt(index)

Parameters

index

0๊ณผ string์˜ length๋ณด๋‹ค -1์ธ ์ •์ˆ˜. ์ธ๋ฑ์Šค๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์œผ๋ฉด default๊ฐ€ 0์ด ๋˜์–ด ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Return value

์ง€์ •๋œ ์ธ๋ฑ์Šค์—์„œ ๋ฌธ์ž(์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ UTF-16์ฝ”๋“œ)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฌธ์ž์—ด์ด๋‹ค.

index ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด

Examples

๋ฌธ์ž์—ด ๋‚ด์˜ ๋‹ค๋ฅธ ์œ„์น˜์— ์žˆ๋Š” ๋ฌธ์ž๋“ค ์ถœ๋ ฅํ•˜๊ธฐ

const anyString = "it will be available to watch until Sunday 11am PT / 2pm ET**";
console.log(`index:0, character: ${anyString.charAt(0)}`);
console.log(`index:1, character: ${anyString.charAt(1)}`);
console.log(`index:2, character: ${anyString.charAt(2)}`);

index:0, character: "i"
index:1, character: "t"
index:2, character: ""

์ „์ฒด๋ฌธ์ž ์–ป๊ธฐ

๋ฌธ์ž์—ด์— ๊ธฐ๋ณธ ๋‹ค๊ตญ์–ด ํ‰๋ฉด์— ์—†๋Š” ๋ฌธ์ž๊ฐ€ ํฌํ•จ ๋œ ๊ฒฝ์šฐ์—๋„ ๋ฌธ์ž์—ด ๋ฃจํ”„๋ฅผ ํ†ต๊ณผํ•  ๋•Œ ํ•ญ์ƒ ์ „์ฒด ๋ฌธ์ž๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•

๋น„๊ตฌ์กฐํ™” ํ• ๋‹น์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ , ๋ฌธ์ž๊ฐ€ surrogate pair๊ฐ€ ๋˜๋Š”๊ฒƒ์„ ํ—ˆ์šฉํ•  ๋•Œ๋Š” ์ฆ๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ž๋™์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๊ธฐ์— ๋” ์œ ์—ฐํ•˜๋‹ค.

https://ko.wikipedia.org/wiki/UTF-16 ๐Ÿง

let str = 'A\uD87E\uDC04Z';

for (var i = 0, chr; i < str.length; i++) {
  console.log(str.charAt(i));
}

// expected output: "A"
// "๏ฟฝ"
// "๏ฟฝ"
// "Z"

console.log(str.charAt(1) + str.charAt(2)) // "ไฝ "

for๋ฌธ์„ ๊ทธ๋ƒฅ ๋Œ๋ฆฌ๋ฉด "๏ฟฝ"

์ด ๋ฌธ์ž์— ์‚ฌ์‹ค ํ•œ์ž 1๊ฐœ์ธ๋ฐ "๏ฟฝ" X 2๊ฐœ๊ฐ€ ๋‚˜์™”๋‹ค. Surrogate pair๋Š” ๋‘๊ฐœ์˜ ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฌธ์ž์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

UTF-16 ์ฝ”๋“œ๊ฐ€ 6๋งŒ 5์ฒœ ๊ธ€์ž๋ฅผ ๋„˜์–ด์„œ๋Š” ๊ธ€์ž๋“ค์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ๋Š”๋ฐ..

Supplementary Characters๋Š” ์œ ๋‹ˆ์ฝ”๋“œ์˜ 2๋ฐ”์ดํŠธ ๊ธฐ๋ณธ ๋ฒ”์œ„์— ์†ํ•˜๋Š” BMP(Basic Multilingual Plane: Plane 0) ์˜์—ญ์„ ๋„˜์–ด์„  ๊ธ€์ž๋“ค์„ ๋งํ•˜๊ณ  Surrogate Pair๋Š” ์ด ๋ฒ”์ฃผ์— ์†ํ•˜๋Š” Supplementary Characters๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด UTF-16์— ๋„์ž…๋œ ์ธ์ฝ”๋”ฉ ๋ฐฉ์‹์ด๋‹ค. 16๋น„ํŠธ ์ฝ”๋“œ ๋‘๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž ํ•˜๋‚˜๋ฅผ ํ‘œํ˜„ํ•œ ๊ฒƒ์„ surrogate pair๋ผ๊ณ  ํ•˜๋ฉฐ high surrogate, low surrogate๋กœ ์ด๋ฃจ์–ด์ง

let str = 'A\uD87E\uDC04Z'; // ๋˜ํ•œ ๋น„ BMP ๋ฌธ์ž๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

for (let i = 0, chr; i < str.length; i++) {
  [chr, i] = getWholeCharAndI(str, i);
  // ์ „์ฒด ๋ฌธ์ž์—ด๊ณผ ํ˜„์žฌ current iterationd์„ ์ „๋‹ฌํ•˜๊ณ 
    // ๊ฐœ๋ณ„ ๋ฌธ์ž์™€ i๊ฐ’์„ ๊ฐ€์ง„ Array๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.(surrogate pair ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ณ€๊ฒฝ๋œ๋‹ค.)

  console.log(chr);
}

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

  if(Number.isNaN(code)) {
    return ''; // ์œ„์น˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ
  }

  if(code < 0xD800 || code > 0xDFFF) {
    return [str.charAt(i), i]; // Normal character, 'i'๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€
  }

  // High surrogate
    // high private surrogates๋ฅผ ๋‹จ์ผ ๋ฌธ์ž๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ์ง€๋ง‰ 16์ง„์ˆ˜๋ฅผ 0xDB7F๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ
  if(0xD800 <= code && code <= 0xDBFF) {
    // 16๋น„ํŠธ ์ฝ”๋“œ ๋‘๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž ํ•˜๋‚˜๋ฅผ ํ‘œํ˜„ํ•œ ๊ฒƒ์„ surrogate pair๋ผ๊ณ  ํ•˜๋ฉฐ high surrogate, low surrogate๋กœ ์ด๋ฃจ์–ด์ง
    // low surrogate๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
    if(str.length <= (i + 1)) {
      throw 'High surrogate without following low surrogate';
    }

    let next = str.charCodeAt(i + 1);
    if(0xDC00 > next || next > 0xDFFF) {
      throw 'High surrogate without following low surrogate';
    }
       return [str.charAt(i) + str.charAt(i + 1), i + 1];
  }

  // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
  if(i === 0) {
    throw 'Low surrogate without preceding high surrogate';
  }
  let prev = str.charCodeAt(i - 1);

  // high private surrogates๋ฅผ ๋‹จ์ผ ๋ฌธ์ž๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ์ง€๋ง‰ 16์ง„์ˆ˜๋ฅผ 0xDB7F๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ
  if(0xD800 > prev || prev > 0xDBFF) {
    throw 'Low surrogate without preceding high surrogate';
  }

  // ๋Œ€์‹  ๋‹ค์Œ ๋ฌธ์ž ๋ฐ˜ํ™˜(๋ฐ ์ฆ๊ฐ€)
  return [str.charAt(i + 1), i + 1];
}

non-Basic-Multilingual-Plane ๋ฌธ์ž๋“ค์„ ์ง€์›ํ•˜๋„๋ก charAt() ๊ณ ์น˜๊ธฐ

non-BMP ๋ฌธ์ž๋“ค์„ ์ง€์›ํ•˜๋Š” ์˜ˆ๋Š” ๐Ÿ‘† ์œ„ ์˜ˆ์ œ๋“ค์ด ๋” ์ž์ฃผ ์‚ฌ์šฉ๋˜์ง€๋งŒ, ์ธ๋ฑ์Šค๋กœ ๋ฌธ์ž๋ฅผ ์„ ํƒํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ๋ฌธ์ž์—ด ๋‚ด์— Surrogate Pair๊ฐ€ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ์ฒ˜๋ฆฌ๋˜๊ธธ ์›ํ•œ๋‹ค๋ฉด! ๐Ÿ‘‡

let str = 'A\uD87E\uDC04Z';

console.log(fixedCharAt(str,1));

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

    let surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
  while ((surrogatePairs.exec(str) != null)) {
    let 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;
}

Last updated

Was this helpful?