๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ‘จ‍๐Ÿ’ป web.dev/fe

์ •๊ทœ์‹์œผ๋กœ camel-case ํŒŒ์‹ฑํ•˜๊ธฐ

by HandHand 2024. 2. 24.

 

๐Ÿ“Œ camelCase๋ฅผ ๋‹จ์–ด ๋‹จ์œ„๋กœ ํŒŒ์‹ฑ ํ•˜๊ธฐ

์ถ•์•ฝ ํ‘œํ˜„(ex. CSS )๋„ ์ง€์›ํ•˜๋ฉด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด camelCase ํ‚ค์›Œ๋“œ๋ฅผ ๋‹จ์–ด ๋‹จ์œ„๋กœ ํŒŒ์‹ฑ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

searchSeoulPOIItems → search seoul poi items

searchSeoulPoiItems → search seoul poi items

CSSProperties → css properties

searchNIMBUS2000BroomStick → search nimbus2000 broom stick

 

์ •๊ทœ์‹์˜ lookbehind ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ•œ๋ฐ, safari๋Š” 16.4๋ถ€ํ„ฐ ์ง€์›ํ•ด์„œ ํฌ๋กœ์Šค๋ธŒ๋ผ์šฐ์ง• ์ด์Šˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ lookbehind๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•ด๊ฒฐํ•ด ๋ณด๊ธฐ

 

์ด์ œ๋ถ€ํ„ฐ 2๊ฐ€์ง€ ๊ณผ์ •์œผ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

  1. ์ „๋ถ€ ๋Œ€๋ฌธ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ์ถ•์•ฝ๋‹จ์–ด๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์ด๋ฅผ lowercase ๋ณ€ํ™˜ + ๋งจ ์•ž์— ๊ณต๋ฐฑ์„ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.
  2. ์ •๊ทœ์‹์œผ๋กœ ๋Œ€๋ฌธ์ž+์†Œ๋ฌธ์ž๋กœ ๊ตฌ์„ฑ๋œ ๊ทœ์น™์„ ์ฐพ์•„ ์ฒ˜๋ฆฌํ•ด์ค๋‹ˆ๋‹ค.

์ด๋•Œ, 1, 2 ๋ชจ๋‘์—์„œ ๋งค์นญ๋œ ๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊ฟ”์ค๋‹ˆ๋‹ค.

 

1๏ธโƒฃ ๋Œ€๋ฌธ์ž๋กœ๋งŒ ๊ตฌ์„ฑ๋œ ์ถ•์•ฝ์–ด ์ฐพ๊ธฐ

์ถ•์•ฝํ‘œํ˜„์„ ํฌํ•จํ•œ ๊ฒฝ์šฐ pointABC, pointABC900 ์ฒ˜๋Ÿผ ๋Œ€๋ฌธ์ž ํ˜น์€ ์ˆซ์ž๋กœ ๋๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ๊ฒฝ๊ณ„๊ตฌ๋ถ„๋งŒ ํ•ด์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •๊ทœ์‹์œผ๋กœ ๋‹จ์–ด๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

 

([A-Z](?=[A-Z0-9])|[A-Z]$)

 

๊ตฌ๋ถ„์€ ํ•ด์คฌ์œผ๋‹ˆ ์ด์ œ ๊ณต๋ฐฑ์ถ”๊ฐ€ + ์†Œ๋ฌธ์ž ๋ณ€ํ™˜ ์„ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„ ์ •๊ทœ์‹์œผ๋กœ ๋Œ€๋ฌธ์ž๋กœ ๊ตฌ์„ฑ๋œ ์•ฝ์ž์˜ ๋งจ ์•ž๊ธ€์ž์—๋งŒ ์•ž์— ๊ณต๋ฐฑ 1๊ฐœ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด ๋งค์นญ๋œ ๋ฌธ์ž์˜ offset์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด์ „์— ๋งค์นญ๋œ ๋ฌธ์ž์˜ offset๊ณผ 2 ์ด์ƒ ์ฐจ์ด๊ฐ€ ๋‚˜๋ฉด ์ƒˆ๋กœ์šด ๋‹จ์–ด๋กœ ๊ตฌ๋ถ„๋จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

function replaceShorthand(str: string) {
  const replacer = createReplacer()

  return str.replace(/([A-Z](?=[A-Z0-9])|[A-Z]$)/g, replacer)
}

function createReplacer() {
  let prevMatchedOffset = -2 // ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ ๋งค์นญ๋œ ๊ฒฝ์šฐ์—๋„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‹œ์ž‘ ๊ฒฝ๊ณ„๊ฐ’์„ -2 ๋กœ ์„ค์ •

  return (match: string, group: unknown, offset: number) => {
    const offsetDiff = offset - prevMatchedOffset
    const needWhiteSpace = offsetDiff > 1 && offset > 0

    prevMatchedOffset = offset

    const whitespace = needWhiteSpace ? ' ' : ''
    return whitespace + match.toLowerCase()
  }
}

 

prevMatchedOffset ์ดˆ๊ธฐ๊ฐ’์ด -2 ์ธ ๊ฒƒ์„ ๋ˆˆ์—ฌ๊ฒจ๋ด…์‹œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งค์นญ๋œ ๋ฌธ์ž์˜ offset ์ด 0์ธ ๊ฒฝ์šฐ์—๋Š” ์•ž์— ๊ณต๋ฐฑ์„ ๋„ฃ์–ด์ฃผ๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

๋งค์นญ๋˜๋Š” ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

searchSeoulPOIItems
           ^^^

CSSProperties
^^^

APC900
^^^

 

์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒŒ์‹ฑ ๋ฉ๋‹ˆ๋‹ค.

 

> input: searchSeoul95GuidePPLAndFood
> output: searchSeoul95Guide pplAndFood

 

โš ๏ธ ์ฃผ์˜ํ•  ์‚ฌํ•ญ

camelCase์—์„œ ์ถ•์•ฝ์–ด๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ํ‘œํ˜„ํ•  ๋•Œ๋Š” ์ถ•์•ฝ์–ด๋’ค์— ์˜ค๋Š” ์ƒˆ๋กœ์šด ๋‹จ์–ด๋Š” ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ทœ์น™์„ ๋ฒ—์–ด๋‚œ ๊ฒฝ์šฐ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๊ตฌ๋ถ„์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

 

POPLandGoods

2๏ธโƒฃ ๋Œ€๋ฌธ์ž+์†Œ๋ฌธ์ž๋กœ ๊ตฌ์„ฑ๋œ ๊ทœ์น™ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์ •๊ทœ์‹์œผ๋กœ ๋Œ€๋ฌธ์ž+์†Œ๋ฌธ์ž n๊ฐœ (ex. Camel) ๋กœ ๊ตฌ์„ฑ๋œ ๋‹จ์–ด๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

 

([A-Z](?=[a-z0-9]))

 

์ด์ œ ํ•ด๋‹น ๋‹จ์–ด์™€ ๋งค์นญ๋˜๋Š” ๋ถ€๋ถ„์„ replace ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„, ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•œ replacer๋กœ ๋™์ผํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
replacer๊ฐ€ ๋ชจ๋“  ๋Œ€๋ฌธ์ž๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊พธ๋˜ ์—ฐ์†๋œ ๋Œ€๋ฌธ์ž๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ ๋Œ€๋ฌธ์ž ์•ž์—๋งŒ ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ createReplacer๋ฅผ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•ด ์ค๋‹ˆ๋‹ค.

 

function replaceCapitalLetter(str: string) {
  const replacer = createReplacer()

  return str.replace(/([A-Z](?=[a-z0-9]))/g, replacer)
}

 

์—ฌ๊ธฐ์„œ ๋งค์นญ๋˜๋Š” ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

searchA9Seoul poiItems
      ^ ^        ^

searchSeoulPoiItems
      ^    ^  ^

cssProperties
   ^

C9
^

 

๐Ÿ“Œ ์œ„์—์„œ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋“ค์„ ํ•ฉ์นฉ๋‹ˆ๋‹ค.

1๋ฒˆ๊ณผ 2๋ฒˆ์—์„œ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” parse ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์‹ฑ ํ•  ๋ฌธ์ž์—ด์„ ์ธ์ž๋กœ ๋ฐ›๊ณ  ์ถ•์•ฝ์–ด ํŒŒ์‹ฑ ๊ณผ ๋Œ€๋ฌธ์ž ํŒŒ์‹ฑ ๊ณผ์ •์„ ๊ฑฐ์ณ์„œ ์ตœ์ข… ๋ฌธ์ž์—ด์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

 

function parse(str: string) {
  const sanitized = replaceShorthand(str)
  const pretty = replaceCapitalLetter(sanitized)

  return pretty
}

 

parse ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

input: searchSeoulGuide
output: search seoul guide

input: searchSeoul95GuidePPLAndFood
output: search seoul95 guide ppl and food
๋ฐ˜์‘ํ˜•

๐Ÿ’ฌ ๋Œ“๊ธ€