옛날에 썼던 JSON Parser 읽기.
늦을 거 없어!(거짓말...16일 현재 공개)
집필을 했지만 소재가 별로 없어 마음이 설렌다.
소재를 찾다가 자신의 GiitHub 창고를 찾았지만 기억하지 못하는 json Parer가 있었어요.(그게 뭐가 무서워)
코드를 살짝 불러내면 재밌을 것 같은 예감이 들기 때문에 json parter 코드를 읽으면서 이해하고, 과거 자신의 코드에 개그 같은 걸 넣어서 같이 놀고 싶어요!
코드의 설명은 잘 하려고 했지만 잡담이 섞인 보도가 되었다!
tumekiri
이번에는 읽을 코드의 개요를 소개하겠습니다.
창고는 여기 있습니다.디덴!
제이슨 파서의 이름은 투미키리라고 합니다.
확실히 이 시기에는 처음 보는 것들의 이름을 짓는다.손톱깎이 근처에 있죠 w
다른 건 멘비라는 창고도 있어요.
이제 이름 짓는 느낌이 들어서 이렇게 되지는 않을 거야!마땅히!대략!
이 JSON Parser(이하 Parser라고 함)는 Rust로 쓴 것이다.
코드는 테스트를 포함하여 모두 300줄로 매우 짧다.(clone을 컴파일한 후 일반적인 동작인 것을 발견하여 기분이 좀 좋았다.)
~/lab/product/tumekiri / - master
:) % tokei
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Markdown 1 16 0 11 5
Rust 2 414 376 3 35
TOML 1 9 6 1 2
===============================================================================
Total 4 439 382 15 42
===============================================================================
테스트 코드 읽기
README가 너무 스팸이어서 아무런 정보도 얻지 못해 테스트 코드를 보면서 파트너의 규격을 보기로 했다.(현재 README, issue,pr의 description 정보도 적기 때문에 변화가 없는 것 같다.)
테스트 용례를 보면 type에 따라 퍼스를 진행할 수 있는지 없는지를 알 수 있다.
#[test]
fn parse_string_test() {
...
}
#[test]
fn parse_number_test() {
...
}
#[test]
fn parse_array_test() {
...
}
#[test]
fn parse_object_test() {
...
}
#[test]
fn parse_bool_and_null_test() {
...
}
가장 복잡한 Object 테스트를 봅시다.#[test]
fn parse_object_test() {
let input = r#"
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower"
}
"#;
let parse_result = JsonParser::new(input.chars()).parse();
assert!(parse_result.is_ok());
let _value = parse_result.unwrap();
// FIXME テスト書くのすごくめんどくさい。。。。プギャーーー
// assert_eq!(value, JsonValue::Object());
}
뭐랄까, 이 코드에 대한 평론은 정말 감탄스럽다...'나 아니야'하는 마음밖에 없어요.
어렵기 때문에 그를 대신해서 시험을 쓰기로 했다.
JsonObject 조립하는 거 되게 싫어하시나 봐요, ww.
이번 시험에 합격했기 때문에 괜찮은 상태에서 일하는 것 같아요.
#[test]
fn parse_object_test() {
let input = r#"
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
}
"#;
let parse_result = JsonParser::new(input.chars()).parse();
let value = parse_result.unwrap();
let h = HashMap::from_iter(
[
(
"squadName".to_owned(),
JsonValue::String("Super hero squad".to_string()),
),
(
"homeTown".to_owned(),
JsonValue::String("Metro City".to_string()),
),
("formed".to_owned(), JsonValue::Number(2016.0)),
(
"secretBase".to_owned(),
JsonValue::String("Super tower".to_string()),
),
]
.iter()
.cloned(),
);
assert_eq!(value, JsonValue::Object(h));
}
code reading
그럼 중요한 이브닝 파티를 읽어볼까요?
테스트 코드를 보고 다음 코드의 input,output을 테스트했습니다.
이에 따라 이번
JsonParser
구조체parse
방법이 접수처가 됐다.JsonParser::new(input.chars()).parse();
JsonParer의 정의를 살펴보겠습니다.열네크스를 낭비하고 있소.ITERATOr TRAIT를 설치하면 뭐든지 할 수 있을 것 같아요.수신된 문자열의 이동전화는 struct
Peekable
로 싸서 사용한다.이거 먼저 읽을 수 있는 이동전화야. 돌려준 거야.이동전화를 추천하지 않으면 다음 값을 먼저 읽을 수 있다.나머지는 행과 열도 있다.(난 Row가 아니라고 생각해,column)
use std::iter::Peekable;
pub struct JsonParser<C: Iterator<Item = char>> {
chars: Peekable<C>,
col: usize,
line: usize,
}
impl<C> JsonParser<C>
where
C: Iterator<Item = char>,
{
pub fn new(input: C) -> Self {
JsonParser {
chars: input.peekable(),
col: 0,
line: 0,
}
}
}
다음 주요 방법을 살펴보겠습니다parse
하는 일은 아래 두 사람처럼 보인다.pub fn parse(&mut self) -> ParseResult {
let first_char = match self.peek() {
None => return self.error_result("Invalid input"),
Some(c) => c,
};
match first_char {
'"' => self.parse_string(),
'0'..='9' | '-' => self.parse_number(),
'{' => self.parse_object(),
'[' => self.parse_array(),
't' | 'f' | 'n' => self.parse_bool_and_null(),
c => self.error_result(&format!("Unsupported charactor {}", c)),
}
}
이때 왜self.나는 넥스트가 아니라 peek이라고 생각했지만 깊이 생각하지 않기로 결정했다처음 한 글자에 커서 같은 거 없나?
peek 방법을 봐도 이유를 잘 모르겠어요.그래.
공백을 넘기면서 줄을 바꾸는 느낌을 잘 처리하면서 input chars를 읽는다.
fn peek(&mut self) -> Option<char> {
while let Some(&c) = self.chars.peek() {
if c == '\n' {
self.col = 0;
self.line += 1;
}
self.col += 1;
if !c.is_whitespace() {
return Some(c);
}
self.chars.next();
}
None
}
너무 힘들어서 마지막parse_string
까지 다 읽어야 돼!300줄 코드를 다 읽기는 어려우니까 포기해!parse_string
호출된 것은peek의 문자가 "
로 결정되어 검사 중입니다.이후 대응하는 닫기
"
를 읽을 때까지 최종 결과output
가 되고 변수를push만 합니다.pub fn parse_string(&mut self) -> ParseResult {
if self.chars.next() != Some('"') {
return self.error_result("");
}
let mut output = String::new();
loop {
let c = match self.chars.next() {
Some('"') => break,
None => return self.error_result(""),
Some(c) => c,
};
output.push(c)
}
Ok(JsonValue::String(output))
}
응.마지막은 간단한 인코딩이지만 괜찮죠.감상
나는 블로그를 쓰면서 코드를 읽으며 심혈을 기울여 매우 기뻤다.
기회가 된다면 누구와 함께 엉엉 코드를 읽고 싶은가.
이번에 다 읽지는 못했지만 300줄 정도의 제이슨 파서로 쓰니까 놀랍네요.더 힘든 프로그램인 것 같아서요.
앞으로도 어딘가에서 코드를 주워서 읽으면서 정리할 거예요!그냥 간단히 하고 있어 난 너무 좋아 www
여기까지 읽어주신 분들도 조금이나마 즐기시면 정말 좋을 것 같아요!
안녕히 주무세요.
Reference
이 문제에 관하여(옛날에 썼던 JSON Parser 읽기.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/nasa/articles/756df75865c79b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)