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