본문으로 바로가기
  1. Home
  2. 그외/유용한 정보
  3. 자바스크립트의 정규식을 활용해 코드 하이라이터 제작하기

자바스크립트의 정규식을 활용해 코드 하이라이터 제작하기

· · 쓰윔

 IT 블로거들은 프로그래밍 언어들을 표시할 때, [**코드 하이라이터**]를 쓰곤 합니다.

 코드 하이라이터는 표시된 코드들을 종류별로 구분해서 다른 색깔로 표시해주는 것으로 독자가 코드를 읽을 때 가독성을 좋게 해주는 효과가 있습니다.

 실제로 저의 블로그에도 아래 사진과 같은 [**코드 하이라이터**]가 적용되어 있습니다.

 

코드하이라이터

 

 코드 하이라이터는 보통 플러그인이나 외부 라이브러리로 불러다 쓰시는 분들이 많습니다. 대표적으로 티스토리에선 [**Syntax Highlight**]라는 플러그인을 제공하기도 합니다.

 

 다만 개인적으론 플러그인에 의존하는 걸 싫어하기도 하거니와, 제가 쓰는 건 javascript/css/html 3종류에 불과한데 여러 언어 기능이 탑재된 플러그인을 쓰는 건 용량 낭비 같아서 직접 제작하기로 했습니다.

 의외로 방법 자체는 간단합니다.

 

[팁*초보를 위해서 마지막 부분에 css/javascript를 올리겠습니다. 그걸 복사해서 블로그/홈페이지에 넣으시면 정상 작동할 겁니다.*]

 

코드 하이라이터의 원리

 

 원리를 요약하자면 이렇습니다.

 

  • 코드하이라이터로 쓸 태그를 찾아냅니다.
  • 찾아낸 태그에서 텍스트를 추출해냅니다.
  • 정규식으로 특정 텍스트를 span으로 감싸줍니다. 이 때 span의 클래스는 원하는 글씨색으로 지정해줍니다.
  • 특정 텍스트를 span으로 감싸줬다면 이걸 다시 코드하이라이터에 주입합니다.

 써놓다보니 복잡해보이지만 실제로는 매우 간단합니다.

 실제 예제를 통해 단계적으로 시도해보겠습니다.

 

code,pre태그를 css로 꾸며주기

 

 첫 단계는 다른 코드하이라이터처럼 꾸미기를 시도하는 겁니다.

 CSS로 작업해주면 됩니다.

 티스토리의 경우 코드블럭을 사용하면 <pre><code></code></pre>로 지정되기 때문에 선택자는 태그로 하면 됩니다.

 이를테면 아래와 같이 해주면 되지요.

 

pre code{
color:#fff;word-break: break-all;
order:3;
	width:100%;
	padding:7px;
	line-height:43px;
	overflow-x: auto;
	position:relative;
}
pre:before,pre:after{
	z-index:5;
	top:-30px;
	position:absolute;
}
pre:after{
	left:5px;
    content: '★';
    color: gold;
    transform-origin: center center;
    display: inline-block;
    -webkit-animation: starstar 3s linear infinite;
	
}

pre:before{
	content: '   'attr(data-ke-language);
	background:#000;
	height:30px;
	color:#fff;
	width:100%;
}
pre {
	margin:50px 0 20px 0;
	position:relative;
min-height:56px;
	color:#fff;
	display:flex;
	 display : -webkit-flex;
 display : -ms-flexbox;
width:100%;
	background: #272822;
		-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;
}

 

 꾸미는 것은 어디까지나 취향의 영역이기 때문에 유저들이 식별하기 좋게 꾸며주는 정도면 충분합니다.

 원하는 대로 꾸미세요.

 어렵지 않을 겁니다. 보통 코드하이라이터는 어둡게 하는 게 대세입니다.

 

코드 블럭을 찾아 텍스트 추출하기

 

 꾸며줬다면 이제 본격적으로 태그에 따라 색깔을 바꿔주거나 효과를 넣어줘야 합니다.

 그러기 위해선 자바스크립트로 제어할 필요가 있습니다.

 이 자바스크립트는 다음과 같은 순서로 진행되야 합니다.

 

  • 본문에서 CODE 태그를 찾아내야 합니다.
  • CODE 태그 내부에 있는 텍스트를 추출해야 합니다.
  • 정규식으로 태그별로 클래스 이름을 붙여주며 감싸주며 태그를 주입합니다.
  • CSS로 클래스 이름에 해당하는 효과를 넣어줍니다.

 여기서 주의해야할 점은 코드하이라이터가 본문에 여러개가 있을 수도 있기 때문에 getElementsByTagName으로 수집한다음에 for문을 써야한다는 겁니다.

 

function codehigh () {
const Content = document.querySelector('.entry-content');//본문선택
if (!Content) {return !1}//본문이 없다면 작업 끝내기
const code = Content.getElementsByTagName('code');//본문내에 있는 CODE태그 선택
if (!code) {return !1} // 본문 내에 code태그가 없다면 작업 끝내기
const codeLength = code.length;//코드태그의 갯수
for (var i =0; i<codeLength; i++) {
 const codeText = code[i].innerHTML;//각 코드태그에 있는 text를 추출하기
 }
 }

  

 제 스킨을 기준으로 보면 본문을 나타내는 건 entry-content라는 Class입니다.

 그걸 querySelector로 선택하고, 그 컨텐츠에서 code 태그를 추출한 후 각 code에 있는 텍스트를 가져오는 거지요.

 설명은 달아놨습니다.

 

 이제 다음 단계로 넘어갈 차례입니다.

 

정규식으로 치환해주기

 

 이제 남은 것은 정규식을 통해 텍스트를 분류하는 겁니다.

 이 때 사용되는 게 정규식의 경계문자 기능입니다.

 표기는 [**\b**]로 해줍니다.

 이 기능을 이용해야 정상적으로 필요한 단어만 잘라올 수 있습니다.

 

정규식설명.jpg

 

 위의 사진을 보시면 이해가 되실 겁니다.

 이 기능을 이용하면 정확히 사용된 코드의 언어만을 감지해줄 수 있습니다.

 

 그 외에도 단어만 감지해주는 \w이나, 특정 문자 사이를 감지해주는 (.*?)이나, 후방탐색을 해서 원하는 만큼의 양을 골라내는 ?=등을 활용하면 됩니다.

 일일히 다 설명하기엔 너무 길므로, 제가 실제로 사용 중인 정규식을 뽑아내보겠습니다.

 

	var strReg1 = /"(.*?)"/g, // 따옴표 사이
    strReg2 = /'(.*?)'/g, // 작은따옴표 사이
    specialReg = /\b(new|var|if|do|function|while|switch|for|foreach|in|continue|break)(?=[^\w])/g, //new var if등 앞에 선언하는 단어
    specialJsGlobReg = /\b(document|window|Array|String|Object|Number|\$)(?=[^\w])/g, //array,string등 자바스크립트에 사용되는 단어
    specialJsReg = /\b(getElementsBy(TagName|ClassName|Name)|getElementById|typeof|instanceof|classList|forEach|(remove|get|set)Attribute|append(Child|)|replaceChild|preventDefault|addEventListener|querySelector(All|)|dataset|inner(HTML|Text)|push|join|concat|pop|shift)(?=[^\w])/g,
    specialMethReg = /\b(indexOf|match|replace|toString|length)(?=[^\w])/g,
    specialPhpReg  = /\b(define|echo|print_r|var_dump)(?=[^\w])/g,
    specialCommentReg  = /(\/\*.*\*\/)/g, //주석1
    inlineCommentReg = /(\/\/.*)/g; // 주석2

var htmlTagReg = /(&lt;[^\&]*&gt;)/g; // <>를 감지

var sqlReg = /\b(CREATE|ALL|DATABASE|TABLE|GRANT|PRIVILEGES|IDENTIFIED|FLUSH|SELECT|UPDATE|DELETE|INSERT|FROM|WHERE|ORDER|BY|GROUP|LIMIT|INNER|OUTER|AS|ON|COUNT|CASE|TO|IF|WHEN|BETWEEN|AND|OR)(?=[^\w])/g;

 

 다른 언어를 사용중이시라면 저 언어의 행태를 보고 적절한 단어를 |  |사이에 넣어주시면 됩니다.

 설명을 생략한 것은 말 그대로 적혀있는 단어를 보고 골라내는 정규식이기 때문입니다.

 

 이제 다음으로 뽑아낸 텍스트에 정규식을 사용해 치환할건데 이럴 때엔 역시 [**replace**]를 사용해주는 게 좋습니다.

 또한 정확히 치환만 해주려면 정규식으로 캡쳐된 부분만을 가져오는 $를 활용해줘야 합니다.

 이 활용법을 이용한다면 이렇습니다.

 

var  parsed = string.replace(strReg1,'<span class="string">"$1"</span>');
    parsed = parsed.replace(strReg2,"<span class=\"string\">'$1'</span>");
    parsed = parsed.replace(specialReg,'<span class="special">$1</span>');
    parsed = parsed.replace(specialJsGlobReg,'<span class="special-js-glob">$1</span>');
    parsed = parsed.replace(specialJsReg,'<span class="special-js">$1</span>');
    parsed = parsed.replace(specialMethReg,'<span class="special-js-meth">$1</span>');
    parsed = parsed.replace(htmlTagReg,'<span class="special-html">$1</span>');
    parsed = parsed.replace(sqlReg,'<span class="special-sql">$1</span>');
    parsed = parsed.replace(specialPhpReg,'<span class="special-php">$1</span>');
    parsed = parsed.replace(specialCommentReg,'<span class="special-comment">$1</span>');
    parsed = parsed.replace(inlineCommentReg,'<span class="special-comment">$1</span>');

  

 parsed라는 변수를 선언해주고, 이걸 차례대로 정규식으로 치환해줍니다.

 그러면 parsed엔 최종적으로 필요한 태그마다 <span>으로 둘러싸인 완성물이 튀어나옵니다.

 이걸 다시 code에 innerHTML로 불어넣으면 끝입니다.

 

 그러면 최종 완성이지만 한 가지 남은 게 바로 css입니다.

 예를 들어 <span class="string">으로 둘러진 글씨 색을 변경해야 하기 때문입니다.

 이 css들은 다음과 같습니다.

 

pre code .string {
    color:#A1E46D;
}
pre code .special {
    color:#D6665D;
}
pre code .special-js {
    color:#6DE4D1;
}
pre code .special-js-glob {
    color:#A1E46D;
    font-weight:bold;
}
pre code .special-comment{
    color:#aaa;
}
pre code .special-js-meth {
    color:#E46D8A;
}
pre code .special-html {
    color:#E4D95F;
}
pre code .special-sql {
    color:#1D968C;
}
pre code .special-php{
    color:#597EA7;
}

 

innerHTML을 배제하기

 

 제가 위에 올린 코드엔 한 가지 약점이 있습니다.

 [**innerHTML**]을 2번 사용했다는 겁니다.

 innerHTML은 자바스크립트 사용시 보안/속도 문제 때문에 가급적 지양해야 합니다. 

 대체할 수 있으면 대체하는 게 옳지요.

 저는 약간의 꼼수를 활용해서 해결했습니다.

 

 먼저 아래의 정규식을 사용해서 innerHTML로 추출하건, textContent로 추출하건 같은 결과가 나오도록 만들었습니다.

 

var htmlTagReg = /(&lt;[^\&]*&gt;)/g;

 

 이제 이 정규식을 사용해 replace를 가장 먼저 해주면 끝입니다.

 이걸로 첫번째 innerHTML은 textContent로 대체할 수 있게 되었습니다.

 그리고 두 번째 innerHTML은 꼼수를 동원했습니다.

 

code.textContent = "";
code.insertAdjacentHTML('afterbegin', parsed);

 

 code에 들어 있는 글자들을 모두 지운 후에, innerHTML대신 insertAdjacentHTML을 활용해 집어넣는 겁니다.

 insertAdjacentHTML의 설명은 이 글을 참고하시면 될 듯 합니다.

 이렇게 해서 innerHTML을 배제해서 코드 하이라이터를 완성했습니다.

 

최종 완성본 실제 모습

 

 위에서 설명한 것들을 종합해 코드하이라이터를 만들었습니다.

 여기 적힌 css/javascript 부분만을 따가면 티스토리나 홈페이지에서도 사용 가능하십니다.

 커스터마이징이 더 필요하겠지만 뼈대는 될 겁니다.

 

 

관련글

무한 스크롤 구현해보기

스크롤 내리면 상단에 고정되는 메뉴 만들어보기

웹폰트 최적화해서 적용하기

간편 메모장
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.

복사하기  저장
× 내용 모두 지우기 내용 모두 복사하기
메모장입니다. 시크릿 모드가 아니면 내용이 저장됩니다.