geo-coordinates-parser 1.7.1 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,6 +46,8 @@ converted.decimalLatitude; // 40.446195 ✓
46
46
  converted.decimalLongitude; // -79.948862 ✓
47
47
  converted.verbatimLatitude; // '40° 26.7717' ✓
48
48
  converted.verbatimLongitude; // '-79° 56.93172' ✓
49
+ converted.decimalCoordinates; // for convenience
50
+ convert.originalFormat; // 'DM' to indicate degrees and minutes
49
51
  ```
50
52
  The returned object includes properties verbatimCoordinates, verbatimLatitude, verbatimLongitude, decimalLatitude, decimalLatitude, and decimalCoordinates.
51
53
 
@@ -23,8 +23,12 @@ function converter(coordsString, decimalPlaces) {
23
23
  let ddLng = null;
24
24
  let latdir = "";
25
25
  let lngdir = "";
26
+ let originalFormat = null;
26
27
  let match = [];
27
28
  let matchSuccess = false;
29
+ if (regex_js_1.dm_invalid.test(coordsString)) {
30
+ throw new Error("invalid coordinate value");
31
+ }
28
32
  if (regex_js_1.dm_numbers.test(coordsString)) {
29
33
  match = regex_js_1.dm_numbers.exec(coordsString);
30
34
  matchSuccess = checkMatch(match);
@@ -37,6 +41,7 @@ function converter(coordsString, decimalPlaces) {
37
41
  if (Number(match[3]) < 0) {
38
42
  ddLng *= -1;
39
43
  }
44
+ originalFormat = "DM";
40
45
  }
41
46
  else {
42
47
  throw new Error("invalid coordinate format");
@@ -55,6 +60,7 @@ function converter(coordsString, decimalPlaces) {
55
60
  if (ddLng.includes(',')) {
56
61
  ddLng = ddLng.replace(',', '.');
57
62
  }
63
+ originalFormat = "DD";
58
64
  //validation, we don't want things like 23.00000
59
65
  //some more validation: no zero coords or degrees only
60
66
  if (Number(Math.round(ddLat)) == Number(ddLat)) {
@@ -84,9 +90,11 @@ function converter(coordsString, decimalPlaces) {
84
90
  ddLat = Math.abs(parseInt(match[2]));
85
91
  if (match[4]) {
86
92
  ddLat += match[4] / 60;
93
+ originalFormat = "DM";
87
94
  }
88
95
  if (match[6]) {
89
96
  ddLat += match[6].replace(',', '.') / 3600;
97
+ originalFormat = "DMS";
90
98
  }
91
99
  if (parseInt(match[2]) < 0) {
92
100
  ddLat = -1 * ddLat;
@@ -122,9 +130,11 @@ function converter(coordsString, decimalPlaces) {
122
130
  ddLat = Math.abs(parseInt(match[2]));
123
131
  if (match[4]) {
124
132
  ddLat += match[4] / 60;
133
+ originalFormat = "DM";
125
134
  }
126
135
  if (match[6]) {
127
136
  ddLat += match[6] / 3600;
137
+ originalFormat = "DMS";
128
138
  }
129
139
  if (parseInt(match[2]) < 0) {
130
140
  ddLat = -1 * ddLat;
@@ -156,13 +166,19 @@ function converter(coordsString, decimalPlaces) {
156
166
  else if (regex_js_1.coords_other.test(coordsString)) {
157
167
  match = regex_js_1.coords_other.exec(coordsString);
158
168
  matchSuccess = checkMatch(match);
169
+ // we need an extra check here for things that matched that shouldn't have
170
+ if (match.filter(x => x).length <= 5) {
171
+ throw new Error("invalid coordinates format");
172
+ }
159
173
  if (matchSuccess) {
160
174
  ddLat = Math.abs(parseInt(match[2]));
161
175
  if (match[4]) {
162
176
  ddLat += match[4].replace(',', '.') / 60;
177
+ originalFormat = "DM";
163
178
  }
164
179
  if (match[6]) {
165
180
  ddLat += match[6].replace(',', '.') / 3600;
181
+ originalFormat = "DMS";
166
182
  }
167
183
  if (parseInt(match[2]) < 0) {
168
184
  ddLat = -1 * ddLat;
@@ -209,6 +225,13 @@ function converter(coordsString, decimalPlaces) {
209
225
  if (latdir && latdir == lngdir) {
210
226
  throw new Error("invalid coordinates format");
211
227
  }
228
+ // a bit of tidying up...
229
+ if (ddLat.toString().includes(',')) {
230
+ ddLat = ddLat.replace(',', '.');
231
+ }
232
+ if (ddLng.toString().includes(',')) {
233
+ ddLng = ddLng.replace(',', '.');
234
+ }
212
235
  //make sure the signs and cardinal directions match
213
236
  let patt = /S|SOUTH/i;
214
237
  if (patt.test(latdir)) {
@@ -284,13 +307,6 @@ function converter(coordsString, decimalPlaces) {
284
307
  if (/^\d+$/.test(verbatimLat) || /^\d+$/.test(verbatimLng)) {
285
308
  throw new Error('degree only coordinate/s provided');
286
309
  }
287
- // last bit of tidying up...
288
- if (isNaN(ddLat) && ddLat.includes(',')) {
289
- ddLat = ddLat.replace(',', '.');
290
- }
291
- if (isNaN(ddLng) && ddLng.includes(',')) {
292
- ddLng = ddLng.replace(',', '.');
293
- }
294
310
  //all done!!
295
311
  //just truncate the decimals appropriately
296
312
  ddLat = Number(Number(ddLat).toFixed(decimalPlaces));
@@ -302,6 +318,7 @@ function converter(coordsString, decimalPlaces) {
302
318
  decimalLatitude: ddLat,
303
319
  decimalLongitude: ddLng,
304
320
  decimalCoordinates: `${ddLat},${ddLng}`,
321
+ originalFormat,
305
322
  closeEnough: coordsCloseEnough,
306
323
  toCoordinateFormat: toCoordinateFormat_js_1.default
307
324
  });
@@ -360,6 +377,9 @@ function decimalsCloseEnough(dec1, dec2) {
360
377
  }
361
378
  }
362
379
  function coordsCloseEnough(coordsToTest) {
380
+ if (!coordsToTest) {
381
+ throw new Error('coords must be provided');
382
+ }
363
383
  if (coordsToTest.includes(',')) {
364
384
  const coords = coordsToTest.split(',');
365
385
  if (Number(coords[0]) == NaN || Number(coords[1]) == NaN) {
@@ -1,3 +1,4 @@
1
+ export const dm_invalid: RegExp;
1
2
  export const dm_numbers: RegExp;
2
3
  export const dd_re: RegExp;
3
4
  export const dms_periods: RegExp;
package/dist/cjs/regex.js CHANGED
@@ -1,19 +1,22 @@
1
1
  "use strict";
2
2
  //Coordinates pattern matching regex
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.coords_other = exports.dms_abbr = exports.dms_periods = exports.dd_re = exports.dm_numbers = void 0;
4
+ exports.coords_other = exports.dms_abbr = exports.dms_periods = exports.dd_re = exports.dm_numbers = exports.dm_invalid = void 0;
5
+ //DM with invalid minutes (goes to coords_other); this is just a shortened version of that to create a guard condition
6
+ const dm_invalid = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([6-9][0-9])\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([6-9][0-9])\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*(EAST|WEST|[EW])?$/i;
7
+ exports.dm_invalid = dm_invalid;
5
8
  //DM as numbers only - see issue #15
6
- const dm_numbers = /([+-]?[0-8]?[0-9])\s+([0-5]?[0-9]\.\d{3,})[\s,]{1,}([+-]?[0-1]?[0-9]?[0-9])\s+([0-5]?[0-9]\.\d{3,})/;
9
+ const dm_numbers = /^([+-]?[0-8]?[0-9])\s+([0-5]?[0-9]\.\d{3,})[\s,]{1,}([+-]?[0-1]?[0-9]?[0-9])\s+([0-5]?[0-9]\.\d{3,})$/;
7
10
  exports.dm_numbers = dm_numbers;
8
11
  //decimal degrees
9
- const dd_re = /(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(EAST|WEST|[EW])?/i;
12
+ const dd_re = /^(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(EAST|WEST|[EW])?$/i;
10
13
  exports.dd_re = dd_re;
11
14
  //degrees minutes seconds with '.' as separator - gives array with 15 values
12
- const dms_periods = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(EAST|WEST|[EW])?/i;
15
+ const dms_periods = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(EAST|WEST|[EW])?$/i;
13
16
  exports.dms_periods = dms_periods;
14
17
  //degrees minutes seconds with words 'degrees, minutes, seconds' as separators (needed because the s of seconds messes with the S of SOUTH) - gives array of 17 values
15
- const dms_abbr = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)\s*(EAST|WEST|[EW])?/i;
18
+ const dms_abbr = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)\s*(EAST|WEST|[EW])?$/i;
16
19
  exports.dms_abbr = dms_abbr;
17
20
  //everything else - gives array of 17 values
18
- const coords_other = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|’’|´´|["″”\.])?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|´´|’’|["″”\.])?\s*(EAST|WEST|[EW])?/i;
21
+ const coords_other = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|’’|´´|["″”\.])?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|´´|’’|["″”\.])?\s*(EAST|WEST|[EW])?$/i;
19
22
  exports.coords_other = coords_other;
@@ -21,6 +21,9 @@ const failingFormats = [
21
21
  'S 90°4\'17.698" S 23°4\'17.698"',
22
22
  '27.45.34 S S 23.23.23',
23
23
  '27.45.34 23.23.23 E',
24
- '8°83S 35°67E '
24
+ '8°83S 35°67E ',
25
+ '25.62S, 27.77E',
26
+ '-254.4602, 31.53681',
27
+ '1234.524234234, 1241.1541241234',
25
28
  ];
26
29
  exports.default = failingFormats;
@@ -9,21 +9,20 @@ const converter_js_1 = __importDefault(require("../converter.js"));
9
9
  //const test = `45°5'46.8134"N, 18°30'36.7124"E`
10
10
  //const test = `50 8.2914,-5 2.4447`
11
11
  //const test = `8°83S 35°67E`
12
- const test = `N 48° 30,6410', E 18° 57,4583'`;
12
+ //const test = `N 48° 30,6410', E 18° 57,4583'`
13
+ //const test = '-254.4602, 31.53681'
14
+ const test = '25.62S, 27.77E';
15
+ //const correctDecimals = '-25.533333, 27.283333'
16
+ let converted;
13
17
  try {
14
- let converted = (0, converter_js_1.default)(test);
15
- console.log(converted);
16
- console.log(converted.toCoordinateFormat(converter_js_1.default.to.DM));
17
- //and just to make sure it's frozen
18
- let previous = converted.decimalLatitude;
19
- converted.decimalLatitude = 24;
20
- if (converted.decimalLatitude === previous) {
21
- console.log('the result is frozen');
22
- }
23
- else {
24
- console.error('!!!The result is not frozen!!!!');
25
- }
18
+ converted = (0, converter_js_1.default)(test);
26
19
  }
27
20
  catch (err) {
28
21
  console.log(err.message);
22
+ process.exit();
23
+ }
24
+ console.log(converted);
25
+ console.log('DM:', converted.toCoordinateFormat(converter_js_1.default.to.DM).replace(/\s/g, '')); // shortened format
26
+ if (!converted.closeEnough(correctDecimals)) {
27
+ console.error('!!! conversion is incorrect !!!');
29
28
  }
@@ -363,6 +363,13 @@ const otherFormats = [
363
363
  verbatimLongitude: `E 18° 57,4583'`,
364
364
  decimalLatitude: 48.51068,
365
365
  decimalLongitude: 18.95764
366
+ },
367
+ {
368
+ verbatimCoordinates: `1.23456, 18.33453`,
369
+ verbatimLatitude: `1.23456`,
370
+ verbatimLongitude: `18.33453`,
371
+ decimalLatitude: 1.23456,
372
+ decimalLongitude: 18.33453
366
373
  }
367
374
  ];
368
375
  function getAllTestFormats() {
@@ -28,8 +28,12 @@ function toCoordinateFormat(format) {
28
28
  const minutesLatitudeNotTruncated = (absoluteLatitude - degreesLatitude) * 60;
29
29
  const minutesLongitudeNotTruncated = (absoluteLongitude - degreesLongitude) * 60;
30
30
  if (format == 'DM') {
31
- const dmMinsLatitude = round(minutesLatitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
32
- const dmMinsLongitude = round(minutesLongitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
31
+ let dmMinsLatitude = round(minutesLatitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
32
+ let dmMinsLongitude = round(minutesLongitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
33
+ if (dmMinsLatitude.endsWith('.000') && dmMinsLongitude.endsWith('.000')) {
34
+ dmMinsLatitude = dmMinsLatitude.replace(/\.000$/, '');
35
+ dmMinsLongitude = dmMinsLongitude.replace(/\.000$/, '');
36
+ }
33
37
  result = `${degreesLatitude}° ${dmMinsLatitude}' ${latDir}, ${degreesLongitude}° ${dmMinsLongitude}' ${longDir}`;
34
38
  }
35
39
  if (format == "DMS") {
@@ -40,9 +44,9 @@ function toCoordinateFormat(format) {
40
44
  const latMinutesString = latMinutes.toString().padStart(2, '0');
41
45
  const longMinutesString = longMinutes.toString().padStart(2, '0');
42
46
  // if they both end in .0 we drop the .0
43
- if (latSeconds.endsWith('.0"') && longSeconds.endsWith('.0"')) {
44
- latSeconds = latSeconds.replace(/\.0"$/, '"');
45
- longSeconds = longSeconds.replace(/\.0"$/, '"');
47
+ if (latSeconds.endsWith('.0') && longSeconds.endsWith('.0')) {
48
+ latSeconds = latSeconds.replace(/\.0$/, '');
49
+ longSeconds = longSeconds.replace(/\.0$/, '');
46
50
  }
47
51
  result = `${degreesLatitude}° ${latMinutesString}' ${latSeconds}" ${latDir}, ${degreesLongitude}° ${longMinutesString}' ${longSeconds}" ${longDir}`;
48
52
  }
@@ -1,6 +1,6 @@
1
1
  //function for converting coordinates from a string to decimal and verbatim
2
2
  //this is just a comment
3
- import { dm_numbers, dd_re, dms_periods, dms_abbr, coords_other } from './regex.js';
3
+ import { dm_invalid, dm_numbers, dd_re, dms_periods, dms_abbr, coords_other } from './regex.js';
4
4
  import toCoordinateFormat from './toCoordinateFormat.js';
5
5
  /**
6
6
  * Function for converting coordinates in a variety of formats to decimal coordinates
@@ -18,8 +18,12 @@ function converter(coordsString, decimalPlaces) {
18
18
  let ddLng = null;
19
19
  let latdir = "";
20
20
  let lngdir = "";
21
+ let originalFormat = null;
21
22
  let match = [];
22
23
  let matchSuccess = false;
24
+ if (dm_invalid.test(coordsString)) {
25
+ throw new Error("invalid coordinate value");
26
+ }
23
27
  if (dm_numbers.test(coordsString)) {
24
28
  match = dm_numbers.exec(coordsString);
25
29
  matchSuccess = checkMatch(match);
@@ -32,6 +36,7 @@ function converter(coordsString, decimalPlaces) {
32
36
  if (Number(match[3]) < 0) {
33
37
  ddLng *= -1;
34
38
  }
39
+ originalFormat = "DM";
35
40
  }
36
41
  else {
37
42
  throw new Error("invalid coordinate format");
@@ -50,6 +55,7 @@ function converter(coordsString, decimalPlaces) {
50
55
  if (ddLng.includes(',')) {
51
56
  ddLng = ddLng.replace(',', '.');
52
57
  }
58
+ originalFormat = "DD";
53
59
  //validation, we don't want things like 23.00000
54
60
  //some more validation: no zero coords or degrees only
55
61
  if (Number(Math.round(ddLat)) == Number(ddLat)) {
@@ -79,9 +85,11 @@ function converter(coordsString, decimalPlaces) {
79
85
  ddLat = Math.abs(parseInt(match[2]));
80
86
  if (match[4]) {
81
87
  ddLat += match[4] / 60;
88
+ originalFormat = "DM";
82
89
  }
83
90
  if (match[6]) {
84
91
  ddLat += match[6].replace(',', '.') / 3600;
92
+ originalFormat = "DMS";
85
93
  }
86
94
  if (parseInt(match[2]) < 0) {
87
95
  ddLat = -1 * ddLat;
@@ -117,9 +125,11 @@ function converter(coordsString, decimalPlaces) {
117
125
  ddLat = Math.abs(parseInt(match[2]));
118
126
  if (match[4]) {
119
127
  ddLat += match[4] / 60;
128
+ originalFormat = "DM";
120
129
  }
121
130
  if (match[6]) {
122
131
  ddLat += match[6] / 3600;
132
+ originalFormat = "DMS";
123
133
  }
124
134
  if (parseInt(match[2]) < 0) {
125
135
  ddLat = -1 * ddLat;
@@ -151,13 +161,19 @@ function converter(coordsString, decimalPlaces) {
151
161
  else if (coords_other.test(coordsString)) {
152
162
  match = coords_other.exec(coordsString);
153
163
  matchSuccess = checkMatch(match);
164
+ // we need an extra check here for things that matched that shouldn't have
165
+ if (match.filter(x => x).length <= 5) {
166
+ throw new Error("invalid coordinates format");
167
+ }
154
168
  if (matchSuccess) {
155
169
  ddLat = Math.abs(parseInt(match[2]));
156
170
  if (match[4]) {
157
171
  ddLat += match[4].replace(',', '.') / 60;
172
+ originalFormat = "DM";
158
173
  }
159
174
  if (match[6]) {
160
175
  ddLat += match[6].replace(',', '.') / 3600;
176
+ originalFormat = "DMS";
161
177
  }
162
178
  if (parseInt(match[2]) < 0) {
163
179
  ddLat = -1 * ddLat;
@@ -204,6 +220,13 @@ function converter(coordsString, decimalPlaces) {
204
220
  if (latdir && latdir == lngdir) {
205
221
  throw new Error("invalid coordinates format");
206
222
  }
223
+ // a bit of tidying up...
224
+ if (ddLat.toString().includes(',')) {
225
+ ddLat = ddLat.replace(',', '.');
226
+ }
227
+ if (ddLng.toString().includes(',')) {
228
+ ddLng = ddLng.replace(',', '.');
229
+ }
207
230
  //make sure the signs and cardinal directions match
208
231
  let patt = /S|SOUTH/i;
209
232
  if (patt.test(latdir)) {
@@ -279,13 +302,6 @@ function converter(coordsString, decimalPlaces) {
279
302
  if (/^\d+$/.test(verbatimLat) || /^\d+$/.test(verbatimLng)) {
280
303
  throw new Error('degree only coordinate/s provided');
281
304
  }
282
- // last bit of tidying up...
283
- if (isNaN(ddLat) && ddLat.includes(',')) {
284
- ddLat = ddLat.replace(',', '.');
285
- }
286
- if (isNaN(ddLng) && ddLng.includes(',')) {
287
- ddLng = ddLng.replace(',', '.');
288
- }
289
305
  //all done!!
290
306
  //just truncate the decimals appropriately
291
307
  ddLat = Number(Number(ddLat).toFixed(decimalPlaces));
@@ -297,6 +313,7 @@ function converter(coordsString, decimalPlaces) {
297
313
  decimalLatitude: ddLat,
298
314
  decimalLongitude: ddLng,
299
315
  decimalCoordinates: `${ddLat},${ddLng}`,
316
+ originalFormat,
300
317
  closeEnough: coordsCloseEnough,
301
318
  toCoordinateFormat
302
319
  });
@@ -355,6 +372,9 @@ function decimalsCloseEnough(dec1, dec2) {
355
372
  }
356
373
  }
357
374
  function coordsCloseEnough(coordsToTest) {
375
+ if (!coordsToTest) {
376
+ throw new Error('coords must be provided');
377
+ }
358
378
  if (coordsToTest.includes(',')) {
359
379
  const coords = coordsToTest.split(',');
360
380
  if (Number(coords[0]) == NaN || Number(coords[1]) == NaN) {
@@ -1,3 +1,4 @@
1
+ export const dm_invalid: RegExp;
1
2
  export const dm_numbers: RegExp;
2
3
  export const dd_re: RegExp;
3
4
  export const dms_periods: RegExp;
package/dist/mjs/regex.js CHANGED
@@ -1,12 +1,14 @@
1
1
  //Coordinates pattern matching regex
2
+ //DM with invalid minutes (goes to coords_other); this is just a shortened version of that to create a guard condition
3
+ const dm_invalid = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([6-9][0-9])\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([6-9][0-9])\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*(EAST|WEST|[EW])?$/i;
2
4
  //DM as numbers only - see issue #15
3
- const dm_numbers = /([+-]?[0-8]?[0-9])\s+([0-5]?[0-9]\.\d{3,})[\s,]{1,}([+-]?[0-1]?[0-9]?[0-9])\s+([0-5]?[0-9]\.\d{3,})/;
5
+ const dm_numbers = /^([+-]?[0-8]?[0-9])\s+([0-5]?[0-9]\.\d{3,})[\s,]{1,}([+-]?[0-1]?[0-9]?[0-9])\s+([0-5]?[0-9]\.\d{3,})$/;
4
6
  //decimal degrees
5
- const dd_re = /(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(EAST|WEST|[EW])?/i;
7
+ const dd_re = /^(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))[\s]*([•º°]?)[\s]*(EAST|WEST|[EW])?$/i;
6
8
  //degrees minutes seconds with '.' as separator - gives array with 15 values
7
- const dms_periods = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(EAST|WEST|[EW])?/i;
9
+ const dms_periods = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(\.)\s*([0-5]?[0-9])\s*(\.)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(EAST|WEST|[EW])?$/i;
8
10
  //degrees minutes seconds with words 'degrees, minutes, seconds' as separators (needed because the s of seconds messes with the S of SOUTH) - gives array of 17 values
9
- const dms_abbr = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)\s*(EAST|WEST|[EW])?/i;
11
+ const dms_abbr = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*(D(?:EG)?(?:REES)?)\s*([0-5]?[0-9])\s*(M(?:IN)?(?:UTES)?)\s*((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(S(?:EC)?(?:ONDS)?)\s*(EAST|WEST|[EW])?$/i;
10
12
  //everything else - gives array of 17 values
11
- const coords_other = /(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|’’|´´|["″”\.])?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|´´|’’|["″”\.])?\s*(EAST|WEST|[EW])?/i;
12
- export { dm_numbers, dd_re, dms_periods, dms_abbr, coords_other };
13
+ const coords_other = /^(NORTH|SOUTH|[NS])?\s*([+-]?[0-8]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|’’|´´|["″”\.])?\s*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?\s*([+-]?[0-1]?[0-9]?[0-9])\s*([•º°\.:]|D(?:EG)?(?:REES)?)?\s*,?([0-5]?[0-9](?:[\.,]\d{1,})?)?\s*(['′´’\.:]|M(?:IN)?(?:UTES)?)?\s*,?((?:[0-5]?[0-9])(?:[\.,]\d{1,3})?)?\s*(''|′′|´´|’’|["″”\.])?\s*(EAST|WEST|[EW])?$/i;
14
+ export { dm_invalid, dm_numbers, dd_re, dms_periods, dms_abbr, coords_other };
@@ -19,6 +19,9 @@ const failingFormats = [
19
19
  'S 90°4\'17.698" S 23°4\'17.698"',
20
20
  '27.45.34 S S 23.23.23',
21
21
  '27.45.34 23.23.23 E',
22
- '8°83S 35°67E '
22
+ '8°83S 35°67E ',
23
+ '25.62S, 27.77E',
24
+ '-254.4602, 31.53681',
25
+ '1234.524234234, 1241.1541241234',
23
26
  ];
24
27
  export default failingFormats;
@@ -4,21 +4,20 @@ import convert from '../converter.js';
4
4
  //const test = `45°5'46.8134"N, 18°30'36.7124"E`
5
5
  //const test = `50 8.2914,-5 2.4447`
6
6
  //const test = `8°83S 35°67E`
7
- const test = `N 48° 30,6410', E 18° 57,4583'`;
7
+ //const test = `N 48° 30,6410', E 18° 57,4583'`
8
+ //const test = '-254.4602, 31.53681'
9
+ const test = '25.62S, 27.77E';
10
+ //const correctDecimals = '-25.533333, 27.283333'
11
+ let converted;
8
12
  try {
9
- let converted = convert(test);
10
- console.log(converted);
11
- console.log(converted.toCoordinateFormat(convert.to.DM));
12
- //and just to make sure it's frozen
13
- let previous = converted.decimalLatitude;
14
- converted.decimalLatitude = 24;
15
- if (converted.decimalLatitude === previous) {
16
- console.log('the result is frozen');
17
- }
18
- else {
19
- console.error('!!!The result is not frozen!!!!');
20
- }
13
+ converted = convert(test);
21
14
  }
22
15
  catch (err) {
23
16
  console.log(err.message);
17
+ process.exit();
18
+ }
19
+ console.log(converted);
20
+ console.log('DM:', converted.toCoordinateFormat(convert.to.DM).replace(/\s/g, '')); // shortened format
21
+ if (!converted.closeEnough(correctDecimals)) {
22
+ console.error('!!! conversion is incorrect !!!');
24
23
  }
@@ -361,6 +361,13 @@ const otherFormats = [
361
361
  verbatimLongitude: `E 18° 57,4583'`,
362
362
  decimalLatitude: 48.51068,
363
363
  decimalLongitude: 18.95764
364
+ },
365
+ {
366
+ verbatimCoordinates: `1.23456, 18.33453`,
367
+ verbatimLatitude: `1.23456`,
368
+ verbatimLongitude: `18.33453`,
369
+ decimalLatitude: 1.23456,
370
+ decimalLongitude: 18.33453
364
371
  }
365
372
  ];
366
373
  function getAllTestFormats() {
@@ -26,8 +26,12 @@ function toCoordinateFormat(format) {
26
26
  const minutesLatitudeNotTruncated = (absoluteLatitude - degreesLatitude) * 60;
27
27
  const minutesLongitudeNotTruncated = (absoluteLongitude - degreesLongitude) * 60;
28
28
  if (format == 'DM') {
29
- const dmMinsLatitude = round(minutesLatitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
30
- const dmMinsLongitude = round(minutesLongitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
29
+ let dmMinsLatitude = round(minutesLatitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
30
+ let dmMinsLongitude = round(minutesLongitudeNotTruncated, 3).toFixed(3).padStart(6, '0');
31
+ if (dmMinsLatitude.endsWith('.000') && dmMinsLongitude.endsWith('.000')) {
32
+ dmMinsLatitude = dmMinsLatitude.replace(/\.000$/, '');
33
+ dmMinsLongitude = dmMinsLongitude.replace(/\.000$/, '');
34
+ }
31
35
  result = `${degreesLatitude}° ${dmMinsLatitude}' ${latDir}, ${degreesLongitude}° ${dmMinsLongitude}' ${longDir}`;
32
36
  }
33
37
  if (format == "DMS") {
@@ -38,9 +42,9 @@ function toCoordinateFormat(format) {
38
42
  const latMinutesString = latMinutes.toString().padStart(2, '0');
39
43
  const longMinutesString = longMinutes.toString().padStart(2, '0');
40
44
  // if they both end in .0 we drop the .0
41
- if (latSeconds.endsWith('.0"') && longSeconds.endsWith('.0"')) {
42
- latSeconds = latSeconds.replace(/\.0"$/, '"');
43
- longSeconds = longSeconds.replace(/\.0"$/, '"');
45
+ if (latSeconds.endsWith('.0') && longSeconds.endsWith('.0')) {
46
+ latSeconds = latSeconds.replace(/\.0$/, '');
47
+ longSeconds = longSeconds.replace(/\.0$/, '');
44
48
  }
45
49
  result = `${degreesLatitude}° ${latMinutesString}' ${latSeconds}" ${latDir}, ${degreesLongitude}° ${longMinutesString}' ${longSeconds}" ${longDir}`;
46
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-coordinates-parser",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "A Javascript function for reading a variety of coordinate formats and converting to decimal numbers. Builds on other efforts by returning the verbatim coordinates and the decimal coordinates all in one object.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/merge.js",