fix: improve GPS parsing robustness
This commit is contained in:
@@ -281,6 +281,18 @@ function parseGpsParts(parts: number[]): number | null {
|
||||
return sign * value;
|
||||
}
|
||||
|
||||
function parseGpsFraction(input: string): number | null {
|
||||
const trimmed = input.trim();
|
||||
if (!trimmed) return null;
|
||||
const match = trimmed.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(\d+(?:\.\d+)?)$/);
|
||||
if (!match) return null;
|
||||
const numerator = Number(match[1]);
|
||||
const denominator = Number(match[2]);
|
||||
if (!Number.isFinite(numerator) || !Number.isFinite(denominator)) return null;
|
||||
if (denominator === 0) return null;
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
function parseGpsValue(value: unknown): number | null {
|
||||
if (typeof value === "number") {
|
||||
return Number.isFinite(value) ? value : null;
|
||||
@@ -291,6 +303,8 @@ function parseGpsValue(value: unknown): number | null {
|
||||
if (!trimmed) return null;
|
||||
const direct = Number(trimmed);
|
||||
if (!Number.isNaN(direct)) return direct;
|
||||
const fraction = parseGpsFraction(trimmed);
|
||||
if (fraction !== null) return fraction;
|
||||
const parts = trimmed.match(/-?\d+(?:\.\d+)?/g);
|
||||
if (!parts) return null;
|
||||
return parseGpsParts(parts.map((part) => Number(part)).filter(Number.isFinite));
|
||||
@@ -300,7 +314,19 @@ function parseGpsValue(value: unknown): number | null {
|
||||
const parts = value
|
||||
.map((part) => {
|
||||
if (typeof part === "number") return part;
|
||||
if (typeof part === "string") return Number(part);
|
||||
if (typeof part === "string") {
|
||||
const fraction = parseGpsFraction(part);
|
||||
if (fraction !== null) return fraction;
|
||||
return Number(part);
|
||||
}
|
||||
if (typeof part === "object" && part !== null) {
|
||||
const candidate = part as Record<string, unknown>;
|
||||
const numerator = Number(candidate.numerator);
|
||||
const denominator = Number(candidate.denominator);
|
||||
if (Number.isFinite(numerator) && Number.isFinite(denominator) && denominator !== 0) {
|
||||
return numerator / denominator;
|
||||
}
|
||||
}
|
||||
return NaN;
|
||||
})
|
||||
.filter(Number.isFinite);
|
||||
@@ -310,9 +336,13 @@ function parseGpsValue(value: unknown): number | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function applyRefSign(value: number, ref: unknown): number {
|
||||
if (typeof ref !== "string") return value;
|
||||
const normalized = ref.trim().toUpperCase();
|
||||
function applyRefSign(value: number, ref: unknown, valueRaw: unknown): number {
|
||||
const refChar = typeof ref === "string" ? ref.trim().toUpperCase() : "";
|
||||
const rawChar =
|
||||
typeof valueRaw === "string"
|
||||
? (valueRaw.trim().match(/[NSEW]/i)?.[0]?.toUpperCase() ?? "")
|
||||
: "";
|
||||
const normalized = refChar || rawChar;
|
||||
if (normalized === "S" || normalized === "W") return -Math.abs(value);
|
||||
if (normalized === "N" || normalized === "E") return Math.abs(value);
|
||||
return value;
|
||||
@@ -325,7 +355,7 @@ function parseGpsCoord(
|
||||
): number | null {
|
||||
const parsed = parseGpsValue(value);
|
||||
if (parsed === null) return null;
|
||||
const signed = applyRefSign(parsed, ref);
|
||||
const signed = applyRefSign(parsed, ref, value);
|
||||
if (!Number.isFinite(signed)) return null;
|
||||
if (kind === "lat") {
|
||||
return signed >= -90 && signed <= 90 ? signed : null;
|
||||
|
||||
Reference in New Issue
Block a user