-
-
Save schan90/db009ff31caa9d66d7295a7132c32094 to your computer and use it in GitHub Desktop.
코드스파츠74 - 3일차 과제 제출: HTML Parser 에 Attribute 해석 기능 추가
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// =============== | |
// === 개정 이력 === | |
// =============== | |
// 2018-01-25 10:07 | |
// 1. IIFE(Immediately Invoked Function Expression) 능력을 과시했으니, 이제 테스트 코드를 주석 걸기 쉽게하기 위해 명명된 함수로 변경 | |
// 2018-01-24 20:07 | |
// 1. textNode 함수를 순수 함수로 개선 | |
// 2018-01-24 19:30 | |
// 1. Attributes 를 children 에서 분리하여 별도의 배열로 저장 | |
// 2. attrNode 함수를 순수 함수로 개선 | |
// 주석? 선수(?!)끼리 왜 이러세요? | |
// 초보를 넘어 람보가 되고 싶다. | |
// 브라우저 개발자 도구에서 콘솔 지우기가 귀찮... | |
clear(); | |
// 브라우저 개발자 도구에서 콘솔에서 "Uncaught SyntaxError: Identifier 'xxx' has already been declared" 가 귀찮... | |
{ | |
'use strict'; | |
const textNode = text => { | |
if(text && text.length) { | |
text = text.substr(text.indexOf('>') + 1); | |
text = text.trim(); | |
return {type:'TEXT', text}; | |
} | |
return null; | |
} | |
const attrNode = startTag => { | |
const attributes = []; | |
findIndexForFirstSpace = startTag.indexOf(" "); | |
if (findIndexForFirstSpace !== -1) { | |
const attrs = startTag.substr(findIndexForFirstSpace + 1).split(/['"] /g); | |
for(const attr of attrs) { | |
[name, text] = attr.split("="); | |
text = text.replace(/['"]/g, '') | |
attributes.push({type: 'ATTR', name, text}); | |
} | |
} | |
return attributes; | |
} | |
const elementNode = (input, cursor, text, stack, stacks) => { | |
const char = input[cursor++]; | |
let isBreak = false; | |
if (char === '<') { | |
if (!!text) { | |
const tx = textNode(text); | |
if(tx) stack.tag.children.push(textNode(text)); | |
text = ''; | |
} | |
if(input[cursor++] !== '/'){ | |
let startTag = input.substring(cursor - 1, cursor = input.indexOf('>', cursor)); | |
const isClose = input[cursor - 1] === '/'; | |
if (isClose) { | |
startTag = startTag.substr(0, startTag.length - 1); | |
} | |
const findIndexForFirstSpace = startTag.indexOf(" "); | |
const name = findIndexForFirstSpace == -1? startTag: startTag.substr(0, findIndexForFirstSpace); | |
const tag = {name, type:'NODE', children:[]}; | |
tag.attributes = attrNode(startTag); | |
cursor++; | |
stack.tag.children.push(tag); | |
if(!isClose){ | |
stacks.push({tag, back:stack}); | |
isBreak = true; | |
} | |
} else if (stack.tag.name == input.substring(cursor, input.indexOf('>', cursor))) { | |
stack = stack.back; | |
} | |
} else text += char; | |
return {cursor, text, isBreak, stack}; | |
}; | |
const parser = input => { | |
const result = {tag:{type:'ROOT', children:[]}}, stacks = []; | |
let cursor = 0, stack = result; | |
do { | |
let text = ''; | |
while(cursor < input.length) { | |
const v = elementNode(input, cursor, text, stack, stacks); | |
({cursor, text, stack} = v); | |
if(v.isBreak) break; | |
} | |
} while(stack = stacks.pop()); | |
return result.tag.children; | |
}; | |
const testParser = _ => { | |
// ========================== | |
// === SI 업계의 전설같은 소문 === | |
// ========================== | |
// 이거 보면 당장 도망가라 | |
// 송금 먼저 전화 나중 | |
// 유전주석 무전도망 | |
// by http://emptydream.tistory.com/3757 [빈꿈님의 웹툰일기 필독 요망] | |
const testSet = [ | |
`<div>test</div>`, | |
`<div>test<img/></div>`, | |
`<div>test<a>aa</a>bb</div>`, | |
`<div> | |
a | |
<a>b</a> | |
c | |
<img/> | |
d | |
</div>`, | |
`<div style="color: red">a</div>`, | |
`<div style="color: red; background: blue">a</div>`, | |
`<div style="color: red">a<span id="sp" class="span">b</span></div>`, | |
`<div id="base" style="width: 100%;">a<a>b</a>c<img/>d</div>`, | |
]; | |
for (test of testSet) console.log(test, parser(test)); | |
}; | |
console.time("제발! 빨간 글씨 안 보이게 해주세요.\n총 테스트 시간"); | |
testParser(); | |
console.timeEnd("제발! 빨간 글씨 안 보이게 해주세요.\n총 테스트 시간"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment