[표식찾기 연습]
1단계 코드베이스 선택
owasp-java-html-sanitizer 에서 HtmlLexer 를 이해하기 위해 필요한 코드들
interface TokenStream {
HtmlToken next();
boolean hasNext();
}
abstract class AbstractTokenStream implements TokenStream {
private HtmlToken tok;
public final boolean hasNext() {
if (tok == null) { tok = produce(); }
return tok != null;
}
public HtmlToken next() {
if (this.tok == null) { this.tok = produce(); }
HtmlToken t = this.tok;
if (t == null) { throw new NoSuchElementException(); }
this.tok = null;
return t;
}
protected abstract HtmlToken produce();
}
final class HtmlLexer extends AbstractTokenStream {
private final String input;
private final HtmlInputSplitter splitter;
private State state = State.OUTSIDE_TAG;
public HtmlLexer(String input) {
this.input = input;
this.splitter = new HtmlInputSplitter(input);
}
@Override
protected HtmlToken produce() { ... }
...
}
final class HtmlInputSplitter extends AbstractTokenStream {
@Override
protected HtmlToken produce() { ... }
...
}
final class HtmlToken {
final int start;
final int end;
final HtmlTokenType type;
static HtmlToken instance(int start, int end, HtmlTokenType type) {
return new HtmlToken(start, end, type);
}
boolean tokenInContextMatches(String context, String match) {
int n = end - start;
if (n != match.length()) { return false; }
return context.regionMatches(start, match, 0, n);
}
private HtmlToken(int start, int end, HtmlTokenType type) {
this.start = start;
this.end = end;
this.type = type;
}
}
enum HtmlTokenType {
ATTRNAME,
ATTRVALUE,
QMARKMETA,
COMMENT,
DIRECTIVE, // A directive such as a DOCTYPE declaration.
UNESCAPED,
QSTRING,
TAGBEGIN,
TAGEND,
TEXT,
IGNORABLE,
SERVERCODE,
;
}
2단계 코드 파악: 선택한 메서드나 함수를 파악하고 코드가 하는 일을 요약
전체적인 구조를 다이어그램으로 표현했다. HtmlLex 와 HtmlInputSplitter 둘 다 AbstractTokenStream 을 상속받고 있지만 HtmlInputSplitter 는 HtmlLexer 안에서만 생성되며 사용된다. 왜 그런 계층관계로 표현했을까? 그리고 각각의 produce 가 있게끔 만든 이유가 뭘까?? -> 코드만 보고 왜라는 질문에 답할수 있을까??
아래 테스트코드를 보면 HtmlLexer 를 통해 HtmlToken 결과를 쉽게 이해할 수 있다.
@Test
public static final void testUrlEndingInSlashOutsideQuotes() {
assertTokens(
"<a href=http://foo.com/>Clicky</a>",
"TAGBEGIN: <a",
"ATTRNAME: href",
"ATTRVALUE: http://foo.com/",
"TAGEND: >",
"TEXT: Clicky",
"TAGBEGIN: </a",
"TAGEND: >");
}
디버깅해보니까 아래와 같이 진행된다.
1. HtmlLexer 의 hasNext 실행
2. HtmlLexer 의 produce 실행되고
3. readToken 실행하면 내부적으로 splitter hasNext 실행한다.
4. HtmlInputSplittor 의 produce 실행
5. paseToken 실행
6. HtmlToken 결과리턴 ex) start:0 end:2 type: TAGBEGIN . <b>을 의미
3단계 사용하는 표식의 적극적 확인
설명 : 읽는 도중 '아, 그렇구나'라는 생각이 들면서 그 코드의 의미를 좀 더 이해하게 되면 잠시 멈추고 왜 그렇게 생각했는지를 적어보라. 주석문, 변수명, 메서드명, 임시 저장값 등 어느 것이든 표식이 될 수 있다.
1. 추상 메서드 produce 를 네이밍으로 HtmlToken 객체를 만드는 역할임을 알 수 있다.
2. HtmlLexer.produce -> readToken -> HtmlInputSplittor.produce -> parseToken 순서로 작업되는 것을 알 수 있다. 처음에 readToken 을 수행하지만 값이 없으면 parseToken 을 수행한다.
4단계 회고
- 어떤 표식을 찾았는가?
HtmlLexer, readToken, parseToken, produce
- 찾은 표식들은 코드의 요소인가, 아니면 사람의 언어로 된 정보인가?
둘다.
- 그 표식들은 무엇에 관해 알려주고 있는가?
html 문자열을 파싱해 HtmlToken 객체에 옮긴다. 루프를 통해 하나씩 의미있는 단위로 파싱하고 이후 분석을 진행한다.
- 그 표식들은 코드의 도메인에 대한 지식을 나타내는가?
옙
- 그 표식들은 코드의 기능에 대한 지식을 나타내는가?
옙
[청킹연습]
1단계 코드 선정
interface TokenStream {
HtmlToken next();
boolean hasNext();
}
abstract class AbstractTokenStream implements TokenStream {
private HtmlToken tok;
public final boolean hasNext() {
if (tok == null) { tok = produce(); }
return tok != null;
}
public HtmlToken next() {
if (this.tok == null) { this.tok = produce(); }
HtmlToken t = this.tok;
if (t == null) { throw new NoSuchElementException(); }
this.tok = null;
return t;
}
protected abstract HtmlToken produce();
}
final class HtmlLexer extends AbstractTokenStream {
private final String input;
private final HtmlInputSplitter splitter;
private State state = State.OUTSIDE_TAG;
public HtmlLexer(String input) {
this.input = input;
this.splitter = new HtmlInputSplitter(input);
}
@Override
protected HtmlToken produce() { ... }
...
}
final class HtmlInputSplitter extends AbstractTokenStream {
@Override
protected HtmlToken produce() { ... }
...
}
2단계 코드 파악
설명: 최대 2분을 넘지 않도록 타이머를 설정하고 코드 파악. 시간이 다 되면 코드는 보지 않는다.
3단계 코드 재현
설명: 기억을 되살려 새롭게 코드를 다시 작성
interface TokenStream {
HtmlToken next();
boolean hasNext();
}
abstract class AbstractTokenStream implements TokenStream {
final HtmlToken tok;
@Override
public HtmlToken next() {
if (this.tok == null) { this.tok = produce(); }
}
@Override
public boolean hasNext() {
if (this.tok == null) { this.tok = produce(); }
}
protected abstract HtmlToken produce();
}
final class HtmlLexer extends AbstractTokenStream {
HtmlInputSplitter splitter;
State state = State.OUTSIDE_TAG
@Override
public HtmlToken produce() {
}
}
final class HtmlInputSplitter extends AbstractTokenStream {
@Override
public HtmlToken produce() {
}
}
4단계 회고
- 어느 부분을 쉽게 기억했는가?
전체적인 구조.
- 부분적으로 기억한 코드가 있는가?
next, hasNext 구현부분
- 전체를 다 기억하지 못한 코드가 있는가?
없음
- 기억하지 못한 라인들이 있다면 그 이유가 무엇일까?
- 기억하지 못한 라인에 본인이 익숙하지 않은 프로그래밍 개념이 들어 있지는 않는가?
놉 시간부족
- 기억하지 못한 라인에 본인이 익숙하지 않은 도메인 지식이 있지는 않는가?
놉 시간부족
'연습' 카테고리의 다른 글
프로그래머뇌 청킹연습/표식찾기연습 - 2 (0) | 2022.05.15 |
---|---|
프로그래머뇌 청킹연습/표식찾기연습 - 1 (0) | 2022.05.11 |
[구현] 자물쇠와 열쇠 (0) | 2021.12.06 |
[구현] 문자열 압축 (0) | 2021.11.29 |
[구현] 문자열 재정렬 (0) | 2021.11.21 |