위 Codeup 1308 의 경우 I 999 백두산을 Student라는 객체로 저장해서 문제를 풀이한다. 이런 과정을 parsing이라고 한다.
Parsing
String type으로 되어 있는 데이터를 자바의 Object type으로 바꿔 만드는 행위이다. 이렇게 파싱을 하면 iterator를 사용할 수 있고, 접근제어자를 사용해 자바의 연산을 사용할 수 있다는 장점이 있다. 하나의 큰 String으로 저장할 때보다 객체 타입으로 저장하고 있을 때 검색, 중복 체크 등의 다양한 기능 확장이 가능해진다.
건강보험심사평가원_전국 병의원 및 약국 현황_20230331
공공 데이터 포털에서 제공하는 전국 병의원 및 약국 현황 데이터를 읽어서 파싱하는 작업을 진행하면 다음과 같다. 데이터는 위 사이트에서 다운로드받을 수 있다.
다운로드받은 파일을 열어 보면 위와 같은 여러 칼럼들이 존재하는데, 이중 이름, 연락처, 주소를 받아와서 자바의 객체로 저장하는 파싱 작업을 진행하고자 한다. 이를 위해 Hospital이라는 객체를 만들어 생성자까지 만든 코드는 다음과 같다.
public class Hospital {
String name;
String phoneNumber;
Address address;
public Hospital(String name, String phoneNumber, Address address) {
this.name = name;
this.phoneNumber = phoneNumber;
this.address = address;
}
}
이때 주소의 경우 시, 읍, 동 등 다양한 요소가 결합되어 있기 때문에 주소를 하나의 String으로 관리하는 것이 아니라 주소라는 객체로 따로 저장해 관리하는 것이 더욱 용이할 수 있다. 따라서 주소를 따로 저장하는 Address 클래스를 생성한다.
public class Address {
String city;
String street;
}
프로젝트 디렉토리에 위 엑셀 파일을 저장한 뒤, BufferedReader
를 통해 읽어들인다. 이때 FileReader
라는 자바 지원 클래스를 사용한다.
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileEx {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("./hospital_info.csv"), "EUC-KR"));
System.out.println(br.readLine());
}
}
이때 한글의 경우 인코딩을 지정해 줘야 하는데, Java8의 newBufferedReader()를 쓰는 방법이 있다.
public class ReadFileEx {
public static void main(String[] args) throws IOException {
try(BufferedReader br = Files.newBufferedReader(
Paths.get("hospital_info_0920.csv"), StandardCharsets.UTF_8)){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
파일을 읽어 오는 기능을 main에 구현하지 않고 지금까지 배운 자바의 객체지향적인 프레임을 따라서 getLine이라는 메소드로 따로 빼 준다.
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
public class ReadFileEx {
public List<String> getLines(String fileName) {
List<String> lines = new LinkedList<>();
try (BufferedReader br = Files.newBufferedReader(
Paths.get(fileName), StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) {
lines.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lines;
}
public static void main(String[] args) throws IOException {
ReadFileEx rfe = new ReadFileEx();
List<String> result = rfe.getLines("hospital_info_0920_utf8.csv");
for (int i = 0; i < 10; i++) {
System.out.println(result.get(i));
}
}
}
이 코드를 실행하면 출력되는 화면은 다음과 같다. 이 코드를 이제 파싱 작업하려고 한다.
암호화요양기호,요양기관명,종별코드,종별코드명,시도코드,시도코드명,시군구코드,시군구코드명,읍면동,우편번호,주소,병원홈페이지,개설일자,총의사수,의과일반의 인원수,의과인턴 인원수,의과레지던트 인원수,의과전문의 인원수,치과일반의 인원수,치과인턴 인원수,치과레지던트 인원수,치과전문의 인원수,한방일반의 인원수,한방인턴 인원수,한방레지던트 인원수,한방전문의 인원수,좌표(X),좌표(Y)
JDQ4MTYyMiM1MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ3OSQyNjE4MzIjNDEjJDEjJDgjJDgz,가톨릭대학교인천성모병원,1,상급종합,220000,인천,220003,인천부평구,,,인천광역시 부평구 동수로 56- (부평동),http://www.cmcism.or.kr/,1981-08-06,322,0,24,65,230,1,0,0,2,0,0,0,0,126.7248987,37.4848309
JDQ4MTYyMiM1MSMkMSMkNCMkODkkMzgxMzUxIzExIyQxIyQzIyQ4OSQ0NjEwMDIjNDEjJDEjJDgjJDgz,강릉아산병원,1,상급종합,320000,강원,320100,강릉시,,25440,강원도 강릉시 사천면 방동길 38 (),http://www.gnah.co.kr,1996-07-30,203,5,0,36,160,0,0,0,2,0,0,0,0,128.8578411,37.8184325
JDQ4MTg4MSM1MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ3OSQ0NjEwMDIjNjEjJDEjJDQjJDgz,강북삼성병원,1,상급종합,110000,서울,110016,종로구,,3181,서울특별시 종로구 새문안로 29 (평동),http://www.kbsmc.co.kr,1979-03-24,410,4,25,132,241,3,0,0,5,0,0,0,0,126.96775,37.5684083
JDQ4MTg4MSM1MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ2MiQyNjE4MzIjNjEjJDEjJDQjJDgz,건국대학교병원,1,상급종합,110000,서울,110023,광진구,,5030,서울특별시 광진구 능동로 120-1 (화양동),http://www.kuh.ac.kr,1982-11-16,421,1,37,149,231,0,0,0,3,0,0,0,0,127.0718276,37.5403764
JDQ4MTYyMiM4MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ3OSQyNjEwMDIjNzEjJDEjJDgjJDgz,경북대학교병원,1,상급종합,230000,대구,230006,대구중구,,41944,"대구광역시 중구 동덕로 130 (삼덕동2가, 경북대학교병원)",http://knumc.knu.ac.kr,1910-09-07,477,4,63,192,217,0,0,0,1,0,0,0,0,128.604125,35.866774
JDQ4MTYyMiM4MSMkMSMkNCMkODkkMzgxMzUxIzExIyQxIyQzIyQ5OSQyNjEwMDIjNjEjJDEjJDQjJDgz,경상국립대학교병원,1,상급종합,380000,경남,380500,진주시,,52727,경상남도 진주시 강남로 79 (칠암동),http://www.gnuh.co.kr/,1986-10-13,326,0,37,106,181,1,0,0,1,0,0,0,0,128.0956717,35.1763252
JDQ4MTg4MSM1MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ4OSQzNjEyMjIjODEjJDEjJDIjJDgz,경희대학교병원,1,상급종합,110000,서울,110007,동대문구,,2447,서울특별시 동대문구 경희대로 23 (회기동),http://www.khuh.or.kr/,1971-10-05,468,2,69,161,236,0,0,0,0,0,0,0,0,127.051852,37.5941195
JDQ4MTYyMiM4MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ3OSQyNjEyMjIjNjEjJDEjJDQjJDgz,계명대학교동산병원,1,상급종합,230000,대구,230007,대구달서구,,42601,대구광역시 달서구 달구벌대로 1035 (신당동),http://www.dsmc.or.kr/,1968-04-06,419,1,45,134,235,3,0,0,1,0,0,0,0,128.4801315,35.8538856
JDQ4MTg4MSM1MSMkMSMkMCMkODkkMzgxMzUxIzExIyQxIyQzIyQ2MiQ0NjEwMDIjNjEjJDEjJDAjJDgz,고려대학교의과대학부속구로병원,1,상급종합,110000,서울,110005,구로구,,8308,서울특별시 구로구 구로동로 148 고려대부속구로병원 (구로동),http://guro.kumc.or.kr/main/index.do,1983-08-31,541,1,35,162,311,0,6,16,10,0,0,0,0,126.8848701,37.492052
charset이 문서마다 변할 수도 있기 때문에 객체를 생성할 때마다 생성자를 통해 초기화해 주도록 하고, 이 변수를 활용해 문서를 읽어드리도록 코드를 변경하였다.
public class ReadFileEx implements Reader{
Reader lineReader;
Charset charset;
public ReadFileEx(Charset charset) {
this.charset = charset;
}
public List<String> getLines(String fileName) throws IOException {
List<String> lines = new LinkedList<>();
BufferedReader br = new BufferedReader(new FileReader(fileName, charset));
// BufferedReader에서 loop으로 한줄씩 불러오기
String line;
while ((line = br.readLine()) != null) {
lines.add(line);
}
return lines;
}
public static void main(String[] args) throws IOException {
ReadFileEx rfe = new ReadFileEx(Charset.forName("UTF-8"));
List<String> result = rfe.getLines("hospital_info_0920_utf8.csv");
for (int i = 0; i < 10; i++) {
System.out.println(result.get(i));
}
}
}
이제 불러온 데이터들을 , 기준으로 split 해서 Hospital 객체에 parsing하려고 한다. 한 줄의 String을 받아서 주소 객체와 병원 객체에 저장하는 코드는 다음과 같다.
public Hospital parse(String str) {
String[] splitted = str.split(",");
Address address = new Address(splitted[10], splitted[5], splitted[7]);
Hospital hospital = new Hospital(splitted[1], splitted[11], address);
return hospital;
}
이제 모든 병원 데이터에 대해 이 작업을 진행한 뒤 리스트로 반환하는 기능을 구현하고자 한다.
public List<Hospital> getHospitals(List<String> lines) {
List<Hospital> hospitals = new ArrayList<>();
for (String line : lines) {
hospitals.add(parse(line));
}
return hospitals;
}
병원 데이터가 잘 파싱되었는지 확인해 보기 위해 주소를 출력하는 print 함수를 만들면 다음과 같다.
public void printHospital(List<Hospital> hospitals) {
for (Hospital hospital : hospitals){
System.out.printf("%s %s %s\n", hospital.getName(), hospital.getWebsiteAdress(), hospital.getAddress().getFullAddr());
}
}
먼저 깃허브에 새로운 리포지토리를 만든다.
GitHub Pages
GitHub Pages는 GitHub의 리포지토리에서 직접 HTML, CSS 및 JavaScript 파일을 가져오고 선택적으로 빌드 프로세스를 통해 파일을 실행하고 웹 사이트를 게시하는 정적 사이트 호스팅 서비스이다. 백그라운드에서 Jekyll에 의해 구동되므로 Jekyll 기반 웹사이트를 무료로 호스팅할 수 있는 것이 장점이다.
파일 생성 예시를 보기 위해 index 파일을 하나 생성한다.
Setting → Pages → branch 에서 main으로 바꿔 준다.
Actions에서 build된 것들을 확인할 수 있다.
gem을 설치한다.
sudo gem install bundler
gem install github-pages
gem install jekyll
이후 git 리포지토리를 git clone으로 가져온다.
클론받은 깃 리포지토리에 깃블로그 엔진을 설치한다. 터미널 명령으로 다음을 실행하면 된다.
jekyll new .
bundle install
bundle exec jekyll serve
jekyll server를 띄우면 git blog가 호스팅되는데, 이때 화면이 깨지는 문제가 발생할 수 있다. 이를 해결하기 위해서는 config.yaml 파일을 간단하게 수정해 주면 된다.
config.yaml 파일에서 baseurl과 url만 다음과 같이 수정해 주면 된다.
baseurl: "/내repository이름"
url: "http://내gitID.github.io"