[JS] ์ ๊ท์์ผ๋ก ๊ฒ์์ด ํ์ด๋ผ์ดํธ / ๋ฌธ์์ด ๋งํฌ ๊ฑธ๊ธฐ(Linkify)
๊ฒ์์ฐฝ์ ์
๋ ฅํ ํค์๋์ ์ผ์นํ๋ ๋จ์ด๋ฅผ ํ์ด๋ผ์ดํธ(๊ฐ์กฐ) ํ๊ธฐ ์ํด split
, join
๋ฑ์ ์ฌ์ฉํ ์ ์์ง๋ง ์ฝ๋๊ฐ ๋ค์ ๋ณต์กํด์ง๋ค. ์ ๊ท์์ ์ฌ์ฉํ๋ฉด ๊น๋ํ๊ฒ ๊ตฌํํ ์ ์๋ค.
ํ์ด๋ผ์ดํฐ ํจ์ ์ ์ โผ
const getHighlightedText = (text, query) => {
const re = new RegExp(`(${query})`, 'gi');
if (query !== '' && text.match(re)) {
const parts = text.split(re);
return (
<>
{parts.map((part) =>
part.toLowerCase() === query.toLowerCase() ? (
<mark key={Math.random().toString(36).slice(2)}>{part}</mark>
) : (
part
),
)}
</>
);
}
return text;
};
ํ์ด๋ผ์ดํฐ ํจ์ ์ฌ์ฉ โผ
return (
// ...์๋ต
<h2>{getHighlightedText(headline, term)}</h2>
);
ํ์ด๋ผ์ดํฐ ํจ์ ํบ์๋ณด๊ธฐ
text
์ query
ํ๋ผ๋ฏธํฐ๋ฅผ ์๋์ฒ๋ผ ๋ฐ์๋ค๊ณ ๊ฐ์ ํด๋ณธ๋ค. text
๋ฌธ์ฅ์ alibaba
๋ผ๋ ๋ฌธ์์ด(๋จ์ด)์ด ๋ค์ด๊ฐ ์๋ค๋ฉด ํด๋น ๋ถ๋ถ์ ๋ชจ๋ ํ์ด๋ผ์ดํธ ์ฒ๋ฆฌํด์ผ ํ๋ค(์ฃผํฉ์์ผ๋ก ํ์ํ ๋ถ๋ถ)
// text ํ๋ผ๋ฏธํฐ
'A Chastened Alibaba Tones Down Its Singles alibabaDay Retail Bonanza';
// query ํ๋ผ๋ฏธํฐ
'alibaba';
RegExp ๊ฐ์ฒด ์์ฑ
์ ๊ท์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ()
๋ฒกํฑ๊ณผ ์๊ดํธ๋ก ํ๋ฒ ๊ฐ์ผ ํ (${๋ณ์๋ช
})
ํํ๋ก ์
๋ ฅํด์ค๋ค.
const re = new RegExp(`(${query})`, 'gi'); // /(alibaba)/gi
g
: ์ ์ญ ๊ฒ์ ํ๋๊ทธ. ๋ชจ๋ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํ.g
ํ๋๊ทธ๊ฐ ์์ผ๋ฉด ์ต์ด ๊ฒ์ ๊ฒฐ๊ณผ๋ง ๋ฐํ.i
: ๋์๋ฌธ์ ๊ตฌ๋ถ ์์ ํ๋๊ทธ(insensitive).i
ํ๋๊ทธ๊ฐ ์์ผ๋ฉด ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์์
๊ฒ์ฌํ ํ ์คํธ๊ฐ ์๋์ง ํ์ธ
โquery
ํน์ text
๊ฐ ๋น ๋ฌธ์์ด์ด๊ฑฐ๋, โtext
์ ๋งค์นญ๋๋ query
๊ฐ ์๋ค๋ฉด ํ์ด๋ผ์ดํ
์ ํ ํ์๊ฐ ์์ผ๋ฏ๋ก ์ด์ ๋ํ ์กฐ๊ฑด์ ๊ฑธ์ด์ค๋ค.
if (query !== '' && text.match(re)) {
// ...ํ์ด๋ผ์ดํ
์ถ๊ฐ ๋ก์ง
}
str.match(regexp)
๋ฉ์๋์์ str
์ด ๋น ๋ฌธ์์ด์ด๊ฑฐ๋, ๋งค์นญ๋๋๊ฒ ์์ผ๋ฉด null
์ ๋ฐํํ๋ค. gi
ํ๋๊ทธ๋ฅผ ๋ถ์์ผ๋ฏ๋ก ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๊ณ , ์ฐพ๋ ๋จ์ด๊ฐ ์ฌ๋ฌ๋ฒ ๋ฑ์ฅํ๋ฉด ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
''.match(re); // null
'hello'.match(re); // null
'tencentaLiBaBa'.match(re); // ['aLiBaBa']
'tencentalibabadouyinALIbaba'.match(re); // ['alibaba', 'ALIbaba']
ํ์ด๋ผ์ดํธ ๋จ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก split
ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ query
๋ alibaba
๋ผ๋ ๋ฌธ์์ด์ด๋ฏ๋ก ์ด๋ฅผ ๊ธฐ์ค(๊ตฌ๋ถ์)์ผ๋ก ๋ฐฐ์ด์ ๋ด๊ธด๋ค.
const parts = text.split(re);
// ['A Chastened ', 'Alibaba', ' Tones Down Its Singles ', 'alibaba', 'Day Retail Bonanza']
โญ๏ธ ๋์ฌ๊ฒจ ๋ณผ ์ ์ split
์ ๊ตฌ๋ถ์(seperator)๋ ๋ฐฐ์ด์ ํฌํจ๋๋ค๋ ์ ์ด๋ค. ์ผ๋ฐ์ ์ผ๋ก split
์ ๊ตฌ๋ถ์๋ฅผ ๋ฐฐ์ด์ ํฌํจํ์ง ์๋๋ค. ํ์ง๋ง ๊ตฌ๋ถ์๊ฐ ํฌํ๊ดํธ()
๋ฅผ ํฌํจํ๋ ์ ๊ท์์ด๋ฉด ํฌํ๋ ๊ฒฐ๊ณผ๋ ๋ฐฐ์ด์ ํฌํจ๋๋ค. ํฌํ ๊ดํธ๋ ์ ๊ท์์์ ํํ์์ ํ๋์ ๋จ์๋ก ์ทจ๊ธํ ๋ ์ฌ์ฉํ๋ค.
'12345six789'.split('six'); // ['12345', '789']
'12345six789'.split(/six/); // ['12345', '789']
'12345six789'.split(/(six)/); // ['12345', 'six', '789']
ํ์ด๋ผ์ดํธํ ๋จ์ด์ mark ํ๊ทธ ์ถ๊ฐ
๊ฐ ๋จ์ด๋ฅผ ์๋ฌธ์๋ก ๋ณํํด์ query
๋ฌธ์์ด๊ณผ ๊ฐ๋ค๋ฉด ํด๋น ๋จ์ด์ <mark>
ํ๊ทธ๋ฅผ ์ถ๊ฐํด์ค๋ค.
return (
<>
{parts.map((part) =>
part.toLowerCase() === query.toLowerCase() ? (
<mark key={Math.random().toString(36).slice(2)}>{part}</mark>
) : (
part
),
)}
</>
);
<mark>
ํ๊ทธ๋ ํ์ฌ ๋งฅ๋ฝ๊ณผ ๊ด๋ จ์๋ ํ
์คํธ๋ฅผ ๊ฐ์กฐํ ๋ ์ฌ์ฉํ๋ฉฐ, ๋
ธ๋์ ํ์ด๋ผ์ดํธ ๋ฐฐ๊ฒฝ์ผ๋ก ๋ ๋๋๋ค.
`<mark>`์ `<strong>` ์์์ ์ฐจ์ด์ ์ ๊ธฐ์ตํ์ธ์. ํ ์คํธ์์, `<mark>`๋ ์ฐ๊ด์ฑ์ ๊ฐ์ง ๋ถ๋ถ์, `<strong>`์ ์ค์๋๋ฅผ ๊ฐ์ง ๋ถ๋ถ์ ๋ํ๋ผ ๋ ์ฌ์ฉํฉ๋๋ค. — MDN
ํ์ด๋ผ์ดํธํ ๋จ์ด๊ฐ ๋ง๋ค๋ฉด key
๋ฅผ ์ง์ ํ๊ธฐ ์ ๋งคํ๋ฏ๋ก ๋์ํํ ๋ฌธ์์ด์ ๋ง๋ค์ด์ ์ฌ์ฉํ ์ ์๋ค.
// lib/utils.ts
export const getRandomKey = (id?: string | number) => {
const randomNum = Math.random().toString(36).slice(2);
return id ? `${id}-${randomNum}` : randomNum;
};
Math.random().toString(36).slice(2);
// Math.random() : 0.1656391799983088
// toString(36) : '0.5yo27t64476'
// slice(2) : 'yo27t64476'
Math.random()
: 0์ด์ 1๋ฏธ๋ง์ ๋ถ๋ ์์์ ๋์toString(36)
: 36์ง์๋ก ๋ณํ — toString์ 2~36 ์ฌ์ด์ ์ง์(Radix)๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋๋ค.
๋ฒ์ธ — ๋ฌธ์์ด์ ๋งํฌ ๊ฑธ๊ธฐ(Linkify)
๊ฒ์์ด ํ์ด๋ผ์ดํธ์ ๋น์ทํ ๋ฐฉ๋ฒ์ผ๋ก ๋ฌธ์์ด์ URL์ด ์๋ค๋ฉด <a>
ํ๊ทธ๋ก ๊ฐ์ธ๋ Linkify ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๋ค. http
https
๋ฑ URL๊ณผ ๊ด๋ จ๋ ํ๋กํ ์ฝ์ ์๋ณํ ์ ์๋ ์ ๊ท์์ ์์ฑํ ํ split
๋ฉ์๋์ ๊ตฌ๋ถ์๋ก ์ฌ์ฉํด์ ๋ถ๋ฆฌํ๋ฉด ๋๋ค. ๋ฐฐ์ด์ ๊ฐ ์์๋ก ๋ถ๋ฆฌ๋ ๋ฌธ์์ด์์ ์ ๊ท์์ ๋งค์นญ๋ ๋ฌธ์์ด(๋งํฌ)์ ํญ์ ํ์ ๋ฒ์งธ ์ธ๋ฑ์ค์ ์์นํ๊ฒ ๋๋ค(์ ๊ท์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์).
const regex = /(https?:\/\/\S+)/g; // http ๋ฐ https ๊ตฌ๋ถ
const paragraph = '์๋ฐ์คํฌ๋ฆฝํธ https://ko.javascript.info/intro ๋ ๋ธ๋ผ์ฐ์ ๋ฟ๋ง ์๋๋ผ ์๋ฒ์์๋ ์คํํ ์ ์์ต๋๋ค. ์ด ์ธ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง https://en.wikipedia.org/wiki/JavaScript_engine ์ด๋ผ ๋ถ๋ฆฌ๋ ํน๋ณํ ํ๋ก๊ทธ๋จ์ด ๋ค์ด ์๋ ๋ชจ๋ ๋๋ฐ์ด์ค์์๋ ๋์ํฉ๋๋ค.';
console.log(paragraph.split(regex));
/*
[
'์๋ฐ์คํฌ๋ฆฝํธ ',
'https://ko.javascript.info/intro',
' ๋ ๋ธ๋ผ์ฐ์ ๋ฟ๋ง ์๋๋ผ ์๋ฒ์์๋ ์คํํ ์ ์์ต๋๋ค. ์ด ์ธ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง ',
'https://en.wikipedia.org/wiki/JavaScript_engine',
' ์ด๋ผ ๋ถ๋ฆฌ๋ ํน๋ณํ ํ๋ก๊ทธ๋จ์ด ๋ค์ด ์๋ ๋ชจ๋ ๋๋ฐ์ด์ค์์๋ ๋์ํฉ๋๋ค.'
*/
์ ๋ฐฉ๋ฒ์ ์ด์ฉํด ํ์๋ฒ์งธ ์ธ๋ฑ์ค์ ๋ฌธ์์ด์ <a>
ํ๊ทธ๋ก ๊ฐ์ธ๋๋ก ์์ฑํ๋ฉด ๋๋ค. ์ด๋ฉ์ผ, ํด์ํ๊ทธ ๋ฑ ๋ ์ ๋ฌธ์ ์ธ Linkify๋ฅผ ์ํ๋ค๋ฉด linkifyjs ๊ฐ์ ํนํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ ์ง์ํ๋ค.
// LinkifyText.tsx
import React from 'react';
import { getRandomKey } from 'lib/utils';
export default function LinkifyText({ text }: { text: string }) {
const regex = /(https?:\/\/\S+)/g;
return (
<>
{text.split(regex).map((part, index) =>
index % 2 === 0 ? (
part
) : (
<a
key={getRandomKey(index)} // [๋๋ค key ์์ฑ ์ ํธ ํจ์](https://www.notion.so/TIL-Linkify-e4bb8f6a7527400992ca396e0614d32d?pvs=21)
href={part}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:text-blue-400"
>
{part}
</a>
),
)}
</>
);
}
๋ ํผ๋ฐ์ค
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Algorithm] ํ๋ก๊ทธ๋๋จธ์ค ๋น๋ฐ์ง๋ ๋ฌธ์ ํ์ด (0) | 2024.04.30 |
---|---|
[AWS] EC2 ๋์คํฌ ๊ณต๊ฐ ๋๋ฆฌ๊ธฐ / ์ฌ์ ๊ณต๊ฐ ํ๋ณดํ๊ธฐ (0) | 2024.04.30 |
[JS] Lodash _.memoize ์์ค ์ฝ๋ ํบ์๋ณด๊ธฐ (0) | 2024.04.30 |
[React] ๋ฆฌ์กํธ๋ก ์ค์๊ฐ ๊ฒ์์ฐฝ ๊ตฌํํ๊ธฐ (0) | 2024.04.30 |
[HTML/CSS] ํผ ํ๋(input) ์์ ๋ณ๊ฒฝํ๊ธฐ โ accent-color (0) | 2024.04.29 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[Algorithm] ํ๋ก๊ทธ๋๋จธ์ค ๋น๋ฐ์ง๋ ๋ฌธ์ ํ์ด
[Algorithm] ํ๋ก๊ทธ๋๋จธ์ค ๋น๋ฐ์ง๋ ๋ฌธ์ ํ์ด
2024.04.30 -
[AWS] EC2 ๋์คํฌ ๊ณต๊ฐ ๋๋ฆฌ๊ธฐ / ์ฌ์ ๊ณต๊ฐ ํ๋ณดํ๊ธฐ
[AWS] EC2 ๋์คํฌ ๊ณต๊ฐ ๋๋ฆฌ๊ธฐ / ์ฌ์ ๊ณต๊ฐ ํ๋ณดํ๊ธฐ
2024.04.30 -
[JS] Lodash _.memoize ์์ค ์ฝ๋ ํบ์๋ณด๊ธฐ
[JS] Lodash _.memoize ์์ค ์ฝ๋ ํบ์๋ณด๊ธฐ
2024.04.30 -
[React] ๋ฆฌ์กํธ๋ก ์ค์๊ฐ ๊ฒ์์ฐฝ ๊ตฌํํ๊ธฐ
[React] ๋ฆฌ์กํธ๋ก ์ค์๊ฐ ๊ฒ์์ฐฝ ๊ตฌํํ๊ธฐ
2024.04.30