개요
정규식 공부를 겸하기 위해 url 값을 입력하면 프로토콜, 도메인, 상세경로, url 파라미터를 뽑는 사이트를 만들어봅시다.
JS만으로도 충분히 만들지만 Go를 사용하는 게 목적이니 Go에서 정규식을 다루는 걸 목표로 잡습니다.
URL 구조
URL에 대해서는 다음 사이트를 정리를 잘해둬서 확인하시면 될 것 같습니다.
https://www.beusable.net/blog/?p=4507
간단하게 요약하면
- Protocol : 데이터 교환 방식이며 미리 정해진 포맷을 지켜 송수신을 편하게 하기 위해 만들어진 것으로 http과 https는 Protocol의 종류
- Domain : IP를 사용할 경우 외우기 힘들기에 사용된 값으로 Domain을 IP로 바꿔주는 DNS(Domain Name Server) 덕분에 Domain 값이 자동으로 IP 변환돼서 사용자들이 사이트에 접속할 수 있음
- Path : 사이트 자체의 상세 주소
- Parameter : Query Parameter로도 불리며 http 요청에 변수를 임의로 줄 수 있게 해 주며 위 이미지에서 domain 변수는 "OVERSEA"라는 값을 지님
- Fragment : 북마크로 사이트에 해당하는 ID 값이 있으면 그 위치로 스크롤됨
정규식
문자열에서 특정 형태의 문자열 조합을 찾아낼 수 있게 해주는 게 정규식입니다.
간단하게 "오늘은 2023년 8월 30일입니다"에서 "2023년 8월 30일"이라는 문구만 가져올 수 있게 해주는 게 정규식이죠.
코드
go 프로젝트 폴더를 만들었다는 가정하에 저희는 Go 표준 정규식 라이브러리인 "regexp"와 API 통신을 위한 gorilla/mux를 사용할 것입니다.
go get github.com/gorilla/mux
폴더 구조는 다음과 같습니다.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/style.css">
<title>URL 분석기</title>
</head>
<body>
<div class="regexp-container">
<form id="regexp-form">
<h2>URL 분석기</h2>
<input class="text-input" type="text" id="url-input" placeholder="URL을 입력하세요">
<input class="button-submit" type="submit" value="검증">
<div class="result-container">
<h4>결과</h4>
<ul class="result-list">
</ul>
</div>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.7.0.min.js"
integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<script>
$("#regexp-form").submit(function (e) {
e.preventDefault()
var url = $("#url-input").val();
if (url === "") {
alert("url을 입력해주세요")
} else {
$.post("/regexp", {url: url})
.done(function (response) {
console.log(response)
$(".result-list").empty()
response.forEach(item => {
if (item !== "") {
$(".result-list").append(`<li>${item}</li>`)
}
})
})
.fail(function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
console.log("API 요청 실패:", textStatus, errorThrown);
});
}
})
</script>
</body>
</html>
style.css
.regexp-container{
border: 1px solid black;
max-width: 700px;
text-align: center;
margin: 0 auto;
}
.text-input {
width: 250px;
padding: 3px;
font-size: 15px;
}
.button-submit {
font-size: 15px;
padding: 2px;
}
.regexp-container .result-container {
padding: 10px;
text-align: left;
margin-bottom: 10px;
margin-left: 15px;
}
main.go
package main
import (
"regexp-site/route"
)
func main() {
route.Start(8080)
}
Go의 정규식 표준 라이브러리인 regexp는 후방탐색, 전방탐색을 지원하지 않습니다.
이유는 Go의 특징은 간결성과 호환성을 지키기 위함이라고 합니다만 만약 원하실 경우 별도의 외부 라이브러리를 사용하시면 됩니다.
아래 라이브러리에 경우 지원합니다.
https://github.com/dlclark/regexp2
이제 마지막 코드인 route.go를 채워줍시다.
package route
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
"regexp"
)
func Start(port int64) {
// 라우터 생성
router := mux.NewRouter()
// API 매핑
router.HandleFunc("/regexp", regexpHandler).Methods("POST")
// index.html 매핑
router.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
fmt.Printf("Listening on http://localhost:%d\n", port)
// 서버 실행
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router))
}
func regexpHandler(w http.ResponseWriter, r *http.Request) {
var result []string
var pattern = `^(https?:\/\/)([-\w\.]+)([-\w\/]+)+(\?[-\=\%\w]+)(\&[-\=\%\w]+)+`
url := r.PostFormValue("url")
// 정규식 유효성 검사
regexpVal, err := regexp.Compile(pattern)
if err != nil {
fmt.Println("정규식 오류:", err)
return
}
// 정규식 실행
result = regexpVal.FindStringSubmatch(url)
// 정규식 실행 결과물을 json으로 반환
w.Header().Set("Content-Type", "application/json")
jsonResult, _ := json.Marshal(result)
_, err = w.Write(jsonResult)
if err != nil {
return
}
}
코드가 길지 않아 이해하기 쉬울 것입니다.
regexpVal.FindStringSubmatch에 경우 전체 조건을 충족하는 문자열과 더불어 정규식에서 정의된 ()을 기준으로 () 안에 정규식을 충족하는 부분을 찾아내 slice에 더해 데이터를 반환합니다.
그렇기에 API 결과물이 배열로 오는 것입니다.
사용된 정규식
코드에 경우 어려운 부분이 없고 사실 해당 기능은 JS에서 제공하는 window.location 만 사용하면 다 알아낼 수 있는 정보입니다, 정규식이 목적이므로 정규식에서 사용한 문법은 다음과 같습니다.
- () : 문자열을 묶을 때 사용
- \특수문자 : 특수문자를 사용할 경우 이미 정규식에 예약이 된 기호일 수 있으니 "\"를 붙여 구분할 수 있습니다.
- ^ : 문자열 시작 지점
- ? : 앞에 있는 표현식이 있거나 없거나 (ex : ab? 는 ab 또는 a를 의미)
- \w : 문자열과 _(언더바)
- + : 앞에 있는 표현식이 하나 이상 반복
- [] : [] 안에 있는 것들 중에 하나를 의미
정규식은 훨씬 더 많은 문법이 존재하지만 저는 위의 문법을 사용하여 개발했습니다.
이를 적용하면 (\&[-\=\%\w]+)는 &로 시작하며 -,=,%,문자열,_이 포함된 문자가 하나이상이 반복되는 패턴을 찾는 것이죠
이러면 &name=1234와 같은 값을 찾을 수 있습니다.
마무리
오타 및 피드백(개선방안 또는 다른 스타일의 코드)은 언제나 환영입니다.
감사합니다.
'Go Lang > Study' 카테고리의 다른 글
[GoLang] xls 파일을 xlsx 파일로 바꿔주자 (0) | 2023.09.17 |
---|---|
[GoLang] 자료형을 초과한 큰 수를 계산해보자 (0) | 2023.09.01 |
GoLang으로 느낌 있게 채팅 방 만들어보자 (0) | 2023.08.27 |
Go로 CRUD REST API 만들기 (3) - Bolt DB 연결 (0) | 2023.07.10 |
Go로 CRUD REST API 만들기 (2) (0) | 2023.07.06 |