좌표 데이터 표준화의 필요성
지리 정보 시스템 (GIS) 및 항해 분야에서는 위치 데이터를 처리할 때 일관된 좌표 체계가 필수적입니다. 역사적으로 경도와 위도는 도 (Degree), 분 (Minute), 초 (Second) 로 구성되는 DMS(度分秒) 형식으로 표기되어 왔습니다. 그러나 컴퓨팅 환경과 수치 연산의 효율성을 고려할 때, 소수점을 포함한 십진법 도 (Decimal Degree, DD) 형식이 더 유리합니다.
시스템 간 상호 운용성을 확보하기 위해서는 DMS 문자열을 파싱하여 DD 값으로 변환하는 과정이 필요합니다. 예를 들어, 해양 안전망 (AIS) 에서 수신된 데이터나 종이 지도 상의 좌표를 디지털 맵 서비스에 연동시키는 경우 이러한 변환 로직이 반드시 적용되어야 합니다.
수학적 변환 알고리즘
DMS 를 DD 로 변환하는 기본 수식은 각 단위를 60 진법으로 통일한 뒤 합산하는 형태입니다. 구체적인 계산 논리는 다음과 같습니다.
Decimal_Degree = Degree + (Minute / 60.0) + (Second / 3600.0)
여기에 중요한 변수는 부호 (Sign) 입니다. 남북구와 동서경은 방향에 따라 양수와 음수로 구분됩니다. 일반적으로 북위 (N) 와 동경 (E) 는 양 (+) 이며, 남위 (S) 와 서경 (W) 는 음 (-) 으로 처리해야 정확한 위치를 나타낼 수 있습니다. 또한 입력 데이터에는 방향 표기가 앞에 올 수도 있고 뒤에 올 수도 있으며, 한글과 영문 혼용 등 불규칙성이 존재하므로 전처리 단계가 중요합니다.
자바 환경에서의 로직 구현
자바는 강력한 문자열 매니퓰레이션 기능을 제공하므로 이를 활용하여 유연한 파서(Parser) 를 구축할 수 있습니다. 아래 코드는 기존 방식을 재구성하여 유지보수성을 높인 유틸리티 클래스 예시입니다. 별도의 외부 라이브러리 없이 순수 자바 API 기반으로 작성되었습니다.
먼저 방향성 판단과 문자열 정제를 수행하는 헬퍼 메서드를 정의합니다. 여기에 더해 주어진 입력값의 단위들을 분리하고 산술 연산을 수행하는 메인 로직을 배치했습니다.
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GeoCoordinateConverter {
// 방위 인식 키워드 목록
private static final List<String> POSITIVE_DIRS = Arrays.asList("N", "E", "북", "동");
private static final List<String> NEGATIVE_DIRS = Arrays.asList("S", "W", "남", "서");
/**
* DMS 형식의 문자열을 소수점 도 (DD) 로 변환합니다.
* @param rawInput 변환 대상 좌표 문자열
* @return 변환된 10 진수 좌표 문자열
*/
public static String parseToDecimal(String rawInput) {
if (rawInput == null || rawInput.trim().isEmpty()) {
return "";
}
boolean isNegative = false;
String cleanData = rawInput.trim();
// 1. 부호 결정 로직
for (String dir : NEGATIVE_DIRS) {
if (cleanData.contains(dir)) {
isNegative = true;
break;
}
}
// 2. 불필요한 문자 제거 및 정규화
// 한글/영문 방향 표시자 제거
for (String dir : POSITIVE_DIRS) {
cleanData = cleanData.replace(dir, "");
}
for (String dir : NEGATIVE_DIRS) {
cleanData = cleanData.replace(dir, "");
}
// 특수 기호 정규화 (도, 분, 초 기호를 공백이나 숫자로만 대체 가능하게 처리)
cleanData = cleanData.replaceAll("[°′″\'::]", " ");
// 3. 단위 값 추출 및 계산
// 숫자만 분리하여 배열로 가져옴 (공백 기준으로 split)
String[] values = cleanData.trim().split("\\s+");
double degree = 0;
double minute = 0;
double second = 0;
try {
if (values.length >= 1) degree = Double.parseDouble(values[0]);
if (values.length >= 2) minute = Double.parseDouble(values[1]);
if (values.length >= 3) second = Double.parseDouble(values[2]);
} catch (NumberFormatException e) {
System.err.println("유효하지 않은 숫자 포맷: " + rawInput);
return rawInput;
}
// 4. 최종 DD 계산
double decimalValue = degree + (minute / 60.0) + (second / 3600.0);
return isNegative ? String.format("-%.6f", Math.abs(decimalValue)) : String.format("%.6f", decimalValue);
}
public static void main(String[] args) {
// 다양한 입력 변형에 대한 검증 세트
String[] testCases = {
"北纬 15°08.1′",
"东经 117°50.9′",
"33°25'4.68\"S",
"W117°50.9′",
"N25°04′32\"",
"120°29′20\"E",
"50°16′36″",
"24°50′30\"N",
"西経 118-14.20E"
};
System.out.println("=== 좌표 변환 결과 확인 ===");
for (String coord : testCases) {
String result = parseToDecimal(coord);
System.out.printf("%-30s => %s%n", coord, result);
}
}
}
코드 실행 결과 분석
위 메인 메서드를 실행하면 입력된 다양한 포맷의 도분초 좌표가 일괄적으로 소수점 형태의 경도/위도로 출력됩니다. 특히 방향 문자가 앞뒤에 혼재되거나, 한글/영문이 섞여 있는 경우에도 정규식과 문자 치환 로직을 통해 정상적으로 파싱됩니다.
예를 들어 "33°25'4.68"S"는 서경/남위임을 인식하여 마이너스 부호가 붙어 "-33.426467"로 반환되며, 방향 표시자가 없는 "50°16′36″"은 양수 그대로 처리됩니다. 이 방법은 실제 서비스 배포 시 발생할 수 있는 데이터 불일치 문제를 방지하는 데 효과적입니다.