Revision a5d7d5a5
Added by Andreas Müller almost 7 years ago
cdmlib-model/src/main/java/eu/etaxonomy/cdm/strategy/parser/location/CoordinateConverter.java | ||
---|---|---|
1 |
// $Id$ |
|
2 |
/** |
|
3 |
* Copyright (C) 2009 EDIT |
|
4 |
* European Distributed Institute of Taxonomy |
|
5 |
* http://www.e-taxonomy.eu |
|
6 |
* |
|
7 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
8 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
9 |
* |
|
10 |
* This file is an Java adaption from the orginal CoordinateConverter written by Dominik Mikiewicz |
|
11 |
* @see www.cartomatic.pl |
|
12 |
* @see http://dev.e-taxonomy.eu/svn/trunk/geo/coordinateConverter/CoordinateConverter.cs |
|
13 |
* @see http://gis.miiz.waw.pl/webapps/coordinateconverter/ |
|
14 |
*/ |
|
15 |
package eu.etaxonomy.cdm.strategy.parser.location; |
|
16 |
|
|
17 |
import java.util.ArrayList; |
|
18 |
import java.util.Collections; |
|
19 |
import java.util.Comparator; |
|
20 |
import java.util.List; |
|
21 |
import java.util.regex.Pattern; |
|
22 |
|
|
23 |
import org.apache.log4j.Logger; |
|
24 |
|
|
25 |
/** |
|
26 |
* @author a.mueller |
|
27 |
* @date 07.06.2010 |
|
28 |
* |
|
29 |
*/ |
|
30 |
public class CoordinateConverter { |
|
31 |
@SuppressWarnings("unused") |
|
32 |
private static final Logger logger = Logger.getLogger(CoordinateConverter.class); |
|
33 |
|
|
34 |
//Patterns |
|
35 |
private List<CoordinatePattern> patterns; |
|
36 |
|
|
37 |
|
|
38 |
private class CoordinatePattern{ |
|
39 |
String description; |
|
40 |
String pattern; |
|
41 |
} |
|
42 |
|
|
43 |
|
|
44 |
private Comparator<CustomHemisphereIndicator> lengthComparator = new Comparator<CustomHemisphereIndicator>(){ |
|
45 |
public int compare(CustomHemisphereIndicator ind1, CustomHemisphereIndicator ind2) { |
|
46 |
return Integer.valueOf(ind1.getLength()).compareTo(ind2.getLength()); |
|
47 |
} |
|
48 |
}; |
|
49 |
|
|
50 |
//Class constructor |
|
51 |
public CoordinateConverter() { |
|
52 |
//initialise pattern array |
|
53 |
patterns = new ArrayList<CoordinatePattern>(); |
|
54 |
|
|
55 |
//temp pattern variable |
|
56 |
CoordinatePattern pattern; |
|
57 |
|
|
58 |
|
|
59 |
//variations of DD.DDD with white space characters |
|
60 |
pattern = new CoordinatePattern(); |
|
61 |
pattern.description = "Variation of DD.DDD"; |
|
62 |
pattern.pattern = |
|
63 |
//+/-/Nn/Ss/Ww/EeDD.DDDD |
|
64 |
"(^" + |
|
65 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
66 |
"((\\d{1,3}(\\.|\\,)?(\\s)*$)|(\\d{1,3}(\\.|\\,)\\d+(\\s)*$))" + |
|
67 |
")" + |
|
68 |
////DD.DDDDNn/Ss/Ww/Ee |
|
69 |
"|(^" + |
|
70 |
"(\\s)*((\\d{1,3}(\\.|\\,)?(\\s)*)|(\\d{1,3}(\\.|\\,)\\d+(\\s)*))" + |
|
71 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
72 |
")"; |
|
73 |
patterns.add(pattern); |
|
74 |
|
|
75 |
|
|
76 |
//Variations of DD(\u00B0|d)MM.MMM' with whitespace characters |
|
77 |
pattern = new CoordinatePattern(); |
|
78 |
pattern.description = "Variation of DD(\u00B0|d)MM.MMM('|m)"; |
|
79 |
pattern.pattern = |
|
80 |
"(^" + |
|
81 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
82 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*$)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)?(\u02B9|'|M|m)?$)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*(\u02B9|'|M|m)?(\\s)*$))" + |
|
83 |
")" + |
|
84 |
"|(^" + |
|
85 |
"(\\s)*((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)?(\u02B9|'|M|m)?)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*(\u02B9|'|M|m)?(\\s)*))" + |
|
86 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
87 |
")"; |
|
88 |
patterns.add(pattern); |
|
89 |
|
|
90 |
|
|
91 |
//Variations of DD\u00B0MM'SS.SSS" with whitespace characters |
|
92 |
pattern = new CoordinatePattern(); |
|
93 |
pattern.description = "Variation of DD(\u00B0|d)MM(\u02B9|m)SS.SSS(\u02BA|s)"; |
|
94 |
pattern.pattern = |
|
95 |
//+/-/Nn/Ss/Ww/EeDD\u00B0MM\u02B9SS.SSS |
|
96 |
"(^" + |
|
97 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
98 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*$)" + |
|
99 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)?(\\s)*$)" + |
|
100 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*(\u02BA|\"|''|S|s)?(\\s)*$)" + |
|
101 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*(\u02BA|\"|''|S|s)?(\\s)*$))" + |
|
102 |
")" + |
|
103 |
//DD°MM\u02B9SS.SSSNn/Ss/Ww/Ee |
|
104 |
"|(^(\\s)*" + |
|
105 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*)|" + |
|
106 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)?(\\s)*)|" + |
|
107 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*(\u02BA|\"|''|S|s)?(\\s)*)|" + |
|
108 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*(\u02B9|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*(\u02BA|\"|''|S|s)?(\\s)*))" + |
|
109 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
110 |
")"; |
|
111 |
patterns.add(pattern); |
|
112 |
|
|
113 |
|
|
114 |
//Variations of DD:MM:SS.SSS with whitespace characters |
|
115 |
pattern = new CoordinatePattern(); |
|
116 |
pattern.description = "Variation of DD:MM:SS.SSS"; |
|
117 |
pattern.pattern = |
|
118 |
// +/-/Nn/Ss/Ww/EeDD:MM:SS.SSS |
|
119 |
"(^" + |
|
120 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
121 |
"((\\d{1,3}(\\s)*\\:?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*$))" + |
|
122 |
")" + |
|
123 |
//DD:MM:SS.SSSNn/Ss/Ww/Ee |
|
124 |
"|(^" + |
|
125 |
"(\\s)*((\\d{1,3}(\\s)*\\:?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*))" + |
|
126 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
127 |
")"; |
|
128 |
patterns.add(pattern); |
|
129 |
|
|
130 |
} |
|
131 |
|
|
132 |
|
|
133 |
//tests if a string matches one of the defined patterns |
|
134 |
private int matchPattern(String str){ |
|
135 |
int recognised = -1; |
|
136 |
|
|
137 |
//match the string against each available patern |
|
138 |
for (int i = 0; i < patterns.size(); i++){ |
|
139 |
|
|
140 |
CoordinatePattern pattern = patterns.get(i); |
|
141 |
Pattern regEx = Pattern.compile(pattern.pattern); |
|
142 |
if (regEx.matcher(str).find()) { |
|
143 |
recognised = i; |
|
144 |
break; |
|
145 |
} |
|
146 |
|
|
147 |
} |
|
148 |
return recognised; |
|
149 |
} |
|
150 |
|
|
151 |
|
|
152 |
//gets sign of the coordinate (tests for presence of negative sign) |
|
153 |
private int getSign(String str){ |
|
154 |
|
|
155 |
//This regex checks for the negative hemisphere indicator |
|
156 |
Pattern regexNegative = Pattern.compile("(-|S|s|W|w)"); |
|
157 |
|
|
158 |
//This regex checks if there weren't any other hemisphere indicators |
|
159 |
//it is needed for the specific case of the DDdMMmSSs S |
|
160 |
//so it needs to be ensured there where no positive indicators |
|
161 |
Pattern regexPositive = Pattern.compile("(\\+|N|n|E|e)"); |
|
162 |
|
|
163 |
//if a positive indicator is found no need to search further |
|
164 |
if (regexPositive.matcher(str).find()){ |
|
165 |
return 1; |
|
166 |
}else{ |
|
167 |
//if not check whether there was a negative indicator. if so negate otherwise return positive |
|
168 |
if (regexNegative.matcher(str).find()){ |
|
169 |
return -1; |
|
170 |
}else{ |
|
171 |
return 1; |
|
172 |
} |
|
173 |
} |
|
174 |
} |
|
175 |
|
|
176 |
|
|
177 |
//this checks for the coordinate sign by evaluating user supplied data |
|
178 |
private int getCustomSign(String str){ |
|
179 |
//Note: |
|
180 |
//Indicators are evaluated from the longest ones to the shortes ones |
|
181 |
//So when searching for "P" does not affect "PN" as "PN" is evaluated earlier |
|
182 |
|
|
183 |
|
|
184 |
//search for the presence of indicators |
|
185 |
boolean hasPositive = false; |
|
186 |
boolean hasNegative = false; |
|
187 |
|
|
188 |
//keep previous negative indicators here |
|
189 |
List<String> previousNegatives = new ArrayList<String>(); |
|
190 |
|
|
191 |
//compare the string with user supplied custom pattern |
|
192 |
for (int x = customPtrn.hemisphereIndicators.size() - 1; x >= 0; x--){ |
|
193 |
|
|
194 |
CustomHemisphereIndicator ind = customPtrn.hemisphereIndicators.get(x); |
|
195 |
|
|
196 |
//test here if the indicator exists (has length >0) |
|
197 |
if (ind.getLength() > 0){ |
|
198 |
|
|
199 |
//check if the supplied pattern was marked as case insensitive? |
|
200 |
String caseInsensitive = ""; |
|
201 |
|
|
202 |
if (customPtrn.caseInsensitive){ |
|
203 |
caseInsensitive = "(?i)"; |
|
204 |
} |
|
205 |
|
|
206 |
//create a regex |
|
207 |
Pattern tempRegex = Pattern.compile(caseInsensitive + ind.getIndicator()); |
|
208 |
|
|
209 |
//if a pattern is found |
|
210 |
if (tempRegex.matcher(str).find()){ |
|
211 |
//check whether it's a positive or negative indicator |
|
212 |
if (ind.getPositive()){ |
|
213 |
/* Note: |
|
214 |
* See the note below to understand why checking for previous negatives is performed here |
|
215 |
*/ |
|
216 |
|
|
217 |
//check the previous negatives |
|
218 |
if (previousNegatives.size() != 0){ |
|
219 |
boolean sameNegative = false; |
|
220 |
|
|
221 |
for (int i = previousNegatives.size() - 1; i >= 0; i--){ |
|
222 |
if (ind.getIndicator() == previousNegatives.get(i)){ |
|
223 |
sameNegative = true; |
|
224 |
break; |
|
225 |
} |
|
226 |
} |
|
227 |
|
|
228 |
//mark as positive only if the previously found negative is the same |
|
229 |
if (sameNegative){ |
|
230 |
hasPositive = true; |
|
231 |
} |
|
232 |
|
|
233 |
}else{ //if no negatives before it already marks the sign as positive |
|
234 |
hasPositive = true; |
|
235 |
} |
|
236 |
|
|
237 |
} else { |
|
238 |
/* Note: |
|
239 |
* save the negative indicator here so it can be compared later if a positive wants to overwrite it! |
|
240 |
* in a case a longer negative "Pn" has already been found a shorter positive "P" will not overwrite it |
|
241 |
* and the hasPositive will remain false; |
|
242 |
* In a case a "P" negative indicator has already been found, positive will mark hasPositive and therefore |
|
243 |
* later a default positive value will be returned (if the indicators for positive & negative are the same |
|
244 |
* positive is returned) |
|
245 |
* testing for previous positives is not required since if a hasPositive is already true method will return |
|
246 |
* true anyway |
|
247 |
* |
|
248 |
*/ |
|
249 |
previousNegatives.add(ind.getIndicator()); |
|
250 |
|
|
251 |
hasNegative = true; |
|
252 |
|
|
253 |
} |
|
254 |
} |
|
255 |
} |
|
256 |
|
|
257 |
} |
|
258 |
|
|
259 |
//Note: |
|
260 |
//positive indicator has priority here - if both indicators supplied by the user are the same, a positive is chosen |
|
261 |
//if there were no indicator found in the tested coordinate, a positive value is returned by default |
|
262 |
|
|
263 |
if (hasPositive){ |
|
264 |
return 1; |
|
265 |
} else { |
|
266 |
if (hasNegative) { |
|
267 |
return -1; |
|
268 |
} else { |
|
269 |
return 1; |
|
270 |
} |
|
271 |
} |
|
272 |
} |
|
273 |
|
|
274 |
|
|
275 |
|
|
276 |
//returns a currently used decimal separator |
|
277 |
private String getDecimalSeparator(){ |
|
278 |
//TODO not yet transformed from C# |
|
279 |
// return System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; |
|
280 |
return "."; |
|
281 |
} |
|
282 |
|
|
283 |
|
|
284 |
//replaces comma or dot for current decimal separator |
|
285 |
private String fixDecimalSeparator(String str){ |
|
286 |
//Note: |
|
287 |
//Coma is replaced as parsers often recognise dot as a decimal separator |
|
288 |
//Comma or dot is replaced with a decimal separator here (environment settings) |
|
289 |
//But decimal separator has to be used later too; |
|
290 |
|
|
291 |
String regExReplaceComma = "(\\,|\\.)"; |
|
292 |
str = str.replaceAll(regExReplaceComma, getDecimalSeparator()); |
|
293 |
|
|
294 |
return str; |
|
295 |
} |
|
296 |
|
|
297 |
|
|
298 |
//removes sign |
|
299 |
private String removeSign(String str){ |
|
300 |
String regExRemoveSign = "(\\+|-|S|s|W|w|N|n|E|e)"; |
|
301 |
str = str.replaceAll(regExRemoveSign, ""); |
|
302 |
return str; |
|
303 |
} |
|
304 |
|
|
305 |
//removes custom sign indicators |
|
306 |
private String removeCustomPatternParts(String str){ |
|
307 |
|
|
308 |
/* Note: |
|
309 |
* Symbols are added here so the removing tries to not affect the coordinate too much |
|
310 |
* Strings to be removed then are evaluated from the longest ones to the shortes ones |
|
311 |
* So when searching for "P" does not affect "PN" as "PN" is evaluated earlier |
|
312 |
* */ |
|
313 |
|
|
314 |
//CustomHemisphereIndicator is used here so another object does not have to be created |
|
315 |
//only for the string cleanning |
|
316 |
List<CustomHemisphereIndicator> stringsToRemove = customPtrn.hemisphereIndicators; |
|
317 |
|
|
318 |
//add degree symbol |
|
319 |
CustomHemisphereIndicator stringToRemove = new CustomHemisphereIndicator("Degree", customPtrn.degreeSymbol,customPtrn.degreeSymbol.length(), false); |
|
320 |
stringsToRemove.add(stringToRemove); |
|
321 |
|
|
322 |
//add minute symbol |
|
323 |
stringToRemove = new CustomHemisphereIndicator("Minute", customPtrn.minuteSymbol, customPtrn.minuteSymbol.length(), false); |
|
324 |
stringsToRemove.add(stringToRemove); |
|
325 |
|
|
326 |
//add second symbol |
|
327 |
stringToRemove = new CustomHemisphereIndicator("Second", customPtrn.secondSymbol, customPtrn.secondSymbol.length(), false); |
|
328 |
stringsToRemove.add(stringToRemove); |
|
329 |
|
|
330 |
//sort the list (by element's Length property) |
|
331 |
Collections.sort(stringsToRemove, lengthComparator); |
|
332 |
|
|
333 |
|
|
334 |
// ListSelectionEv.sort(lengthComparator); |
|
335 |
|
|
336 |
|
|
337 |
for (int x = stringsToRemove.size() - 1; x >= 0; x--){ |
|
338 |
|
|
339 |
CustomHemisphereIndicator toBeRemoved = stringsToRemove.get(x); |
|
340 |
|
|
341 |
//check if the string exists so replacing does not yield errors |
|
342 |
if (toBeRemoved.getLength() > 0) |
|
343 |
{ |
|
344 |
//check if the supplied pattern was marked as case insensitive? |
|
345 |
String CaseInsensitive = ""; |
|
346 |
|
|
347 |
if (customPtrn.caseInsensitive){ |
|
348 |
CaseInsensitive = "(?i)"; |
|
349 |
} |
|
350 |
|
|
351 |
//create regex for replacing |
|
352 |
String tempRegex = CaseInsensitive + toBeRemoved.getIndicator(); |
|
353 |
|
|
354 |
|
|
355 |
if (toBeRemoved.getName().equals("Degree") || toBeRemoved.getName().equals("Minute")) { |
|
356 |
//replace with a symbol used later for splitting |
|
357 |
str = str.replaceAll(tempRegex, ":"); |
|
358 |
} else { |
|
359 |
//remove the string |
|
360 |
str = str.replaceAll(tempRegex, ""); |
|
361 |
} |
|
362 |
} |
|
363 |
} |
|
364 |
return str; |
|
365 |
} |
|
366 |
|
|
367 |
|
|
368 |
|
|
369 |
//removes whitespace characters |
|
370 |
private String removeWhiteSpace(String str){ |
|
371 |
str = str.replaceFirst("\\s+", ""); |
|
372 |
return str; |
|
373 |
} |
|
374 |
|
|
375 |
|
|
376 |
//Object for the conversion results |
|
377 |
public class ConversionResults{ |
|
378 |
public boolean patternRecognised; |
|
379 |
public String patternMatched; |
|
380 |
public String patternType; |
|
381 |
|
|
382 |
public boolean conversionSuccessful; |
|
383 |
public double convertedCoord; |
|
384 |
public boolean canBeLat; |
|
385 |
|
|
386 |
public String conversionComments; |
|
387 |
|
|
388 |
public Boolean isLongitude; |
|
389 |
|
|
390 |
public int dd; |
|
391 |
public int mm; |
|
392 |
public double mmm; |
|
393 |
public int ss; |
|
394 |
public double sss; |
|
395 |
|
|
396 |
} |
|
397 |
|
|
398 |
|
|
399 |
public ConversionResults tryConvert(String str){ |
|
400 |
//some local variables |
|
401 |
int sign; //sign of the coordinate |
|
402 |
String[] decimalBit, ddmmss, ddmm; //arrays for splitting |
|
403 |
double dd = 0, mm = 0, ss = 0, mmm = 0, sss = 0, dec = 0; //parts of the coordinates |
|
404 |
|
|
405 |
String decSeparatorRaw = String.valueOf(getDecimalSeparator()); //gets the current decimal separator |
|
406 |
String decSeparatorRegEx = decSeparatorRaw.replace(".", "\\."); |
|
407 |
|
|
408 |
ConversionResults results = new ConversionResults(); |
|
409 |
|
|
410 |
//Get the matched pattern |
|
411 |
CoordinatePattern pattern; |
|
412 |
int ptrnnum = matchPattern(str); |
|
413 |
if (ptrnnum != -1) { |
|
414 |
pattern = patterns.get(ptrnnum); |
|
415 |
} else { |
|
416 |
pattern = new CoordinatePattern(); |
|
417 |
pattern.description = "Unknown"; |
|
418 |
pattern.pattern = "No pattern matched"; |
|
419 |
} |
|
420 |
|
|
421 |
|
|
422 |
|
|
423 |
if (pattern.description.equals("Variation of DD.DDD")){ |
|
424 |
|
|
425 |
//Sets pattern machted, successful, pattern type and pattern info |
|
426 |
initializeResult(results, pattern); |
|
427 |
|
|
428 |
//get sign |
|
429 |
sign = getSign(str); |
|
430 |
results.isLongitude = getIsLongitude(str); |
|
431 |
|
|
432 |
//Replace comma or dot with a current decimal separator |
|
433 |
str = fixDecimalSeparator(str); |
|
434 |
|
|
435 |
//Remove all the unwanted stuff |
|
436 |
str = removeSign(str); |
|
437 |
str = removeWhiteSpace(str); |
|
438 |
|
|
439 |
//Since this is already a decimal degree no spliting is needed |
|
440 |
dd = Double.valueOf(str); |
|
441 |
|
|
442 |
checkDegreeRange(dd, results); |
|
443 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
444 |
|
|
445 |
}else if (pattern.description.equals("Variation of DD(\u00B0|d)MM.MMM('|m)")){ |
|
446 |
|
|
447 |
//Sets pattern machted, successful, pattern type and pattern info |
|
448 |
initializeResult(results, pattern); |
|
449 |
|
|
450 |
//get sign |
|
451 |
sign = getSign(str); |
|
452 |
results.isLongitude = getIsLongitude(str); |
|
453 |
|
|
454 |
//Replace comma or dot with a current decimal separator |
|
455 |
str = fixDecimalSeparator(str); |
|
456 |
|
|
457 |
//Remove all the unwanted stuff |
|
458 |
str = removeSign(str); |
|
459 |
str = removeWhiteSpace(str); |
|
460 |
|
|
461 |
//do some further replacing |
|
462 |
//Replace degree symbol |
|
463 |
str = str.replaceAll("(\u00B0|\u00BA|D|d)", ":"); |
|
464 |
|
|
465 |
//remove minute symbol |
|
466 |
str = str.replaceAll("(\u02B9|'|M|m)", ""); |
|
467 |
|
|
468 |
//Extract decimal part |
|
469 |
decimalBit = str.split(decSeparatorRegEx); |
|
470 |
|
|
471 |
//split degrees and minutes |
|
472 |
ddmm = decimalBit[0].split(":"); |
|
473 |
|
|
474 |
|
|
475 |
//extract values from the strings |
|
476 |
dd = Integer.valueOf(ddmm[0]); //Degrees |
|
477 |
|
|
478 |
if (ddmm.length > 1){ //Minutes |
|
479 |
//check if the string is not empty |
|
480 |
if (ddmm[1] != "") { |
|
481 |
mm = Integer.valueOf(ddmm[1]); |
|
482 |
} |
|
483 |
} |
|
484 |
|
|
485 |
if (decimalBit.length > 1){//DecimalSeconds |
|
486 |
//check if the string is not empty |
|
487 |
if (decimalBit[1] != "") { |
|
488 |
mmm = Double.valueOf(decimalBit[1]) / Math.pow(10, (decimalBit[1].length())); |
|
489 |
} |
|
490 |
} |
|
491 |
|
|
492 |
checkDegreeRange(dd, results); |
|
493 |
checkMinuteRange(mm, results); |
|
494 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
495 |
|
|
496 |
}else if (pattern.description.equals("Variation of DD(\u00B0|d)MM(\u02B9|m)SS.SSS(\u02BA|s)")){ |
|
497 |
|
|
498 |
/* |
|
499 |
* Note: |
|
500 |
* This pattern allows the seconds to be specified with S, s or " or nothing at all |
|
501 |
* If the seconds are marked with "s" and there is no other indication of the hemisphere |
|
502 |
* the coordinate will be parsed as southern (negative). |
|
503 |
* |
|
504 |
* If the N / E / W / + indicator is found the coordinate will be parsed appropriately no matter |
|
505 |
* what is the second notation |
|
506 |
*/ |
|
507 |
|
|
508 |
//Sets pattern machted, successful, pattern type and pattern info |
|
509 |
initializeResult(results, pattern); |
|
510 |
|
|
511 |
//get sign |
|
512 |
sign = getSign(str); |
|
513 |
//TODO test S |
|
514 |
results.isLongitude = getIsLongitude(str); |
|
515 |
|
|
516 |
//Replace comma or dot with a current decimal separator |
|
517 |
str = fixDecimalSeparator(str); |
|
518 |
|
|
519 |
//Remove all the unwanted stuff |
|
520 |
str = removeSign(str); |
|
521 |
str = removeWhiteSpace(str); |
|
522 |
|
|
523 |
//remove second symbol (s is removed by the get sign method) |
|
524 |
//double apostrophe is not removed here as single apostrphe may mark minutes! |
|
525 |
//it's taken care of later after extracting the decimal part |
|
526 |
str = str.replaceAll("(\u02BA|\")", ""); |
|
527 |
|
|
528 |
//do some further replacing |
|
529 |
//Replace degree symbol |
|
530 |
str = str.replaceAll("(\u00B0|\u00B0|D|d|\u02B9|'|M|m)",":"); |
|
531 |
|
|
532 |
//Extract decimal part |
|
533 |
decimalBit = str.split(decSeparatorRegEx); |
|
534 |
|
|
535 |
//remove : from the decimal part [1]! This is needed when a double apostrophe was used to mark seconds |
|
536 |
if (decimalBit.length > 1) |
|
537 |
{ |
|
538 |
decimalBit[1].replace(":", ""); |
|
539 |
} |
|
540 |
|
|
541 |
//split degrees and minutes |
|
542 |
ddmmss = decimalBit[0].split(":"); |
|
543 |
|
|
544 |
|
|
545 |
//extract values from the strings |
|
546 |
dd = Integer.valueOf(ddmmss[0]); //Degrees |
|
547 |
if (ddmmss.length > 1){//Minutes |
|
548 |
//check if the string is not empty |
|
549 |
if (ddmmss[1] != "") { |
|
550 |
mm = Integer.valueOf(ddmmss[1]); |
|
551 |
} |
|
552 |
} |
|
553 |
if (ddmmss.length > 2){//Seconds |
|
554 |
//check if the string is not empty |
|
555 |
if (ddmmss[2] != "") { |
|
556 |
ss = Integer.valueOf(ddmmss[2]); |
|
557 |
} |
|
558 |
} |
|
559 |
if (decimalBit.length > 1) { //DecimalSeconds |
|
560 |
//check if the string is not empty |
|
561 |
if (decimalBit[1] != "") { |
|
562 |
sss = Double.valueOf(decimalBit[1]) / Math.pow(10, (decimalBit[1].length())); |
|
563 |
} |
|
564 |
} |
|
565 |
|
|
566 |
checkDegreeRange(dd, results); |
|
567 |
checkMinuteRange(mm, results); |
|
568 |
checkSecondRange(ss, results); |
|
569 |
|
|
570 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
571 |
|
|
572 |
}else if (pattern.description.equals("Variation of DD:MM:SS.SSS")){ |
|
573 |
|
|
574 |
//Sets pattern machted, successful, pattern type and pattern info |
|
575 |
initializeResult(results, pattern); |
|
576 |
|
|
577 |
//get sign |
|
578 |
sign = getSign(str); |
|
579 |
results.isLongitude = getIsLongitude(str); |
|
580 |
|
|
581 |
//Replace comma or dot with a current decimal separator |
|
582 |
str = fixDecimalSeparator(str); |
|
583 |
|
|
584 |
//Remove all the unwanted stuff |
|
585 |
str = removeSign(str); |
|
586 |
str = removeWhiteSpace(str); |
|
587 |
|
|
588 |
//Do some splitting |
|
589 |
decimalBit = str.split(decSeparatorRegEx); |
|
590 |
ddmmss = decimalBit[0].split(":"); |
|
591 |
|
|
592 |
|
|
593 |
//extract values from the strings |
|
594 |
dd = Integer.valueOf(ddmmss[0]); //Degrees |
|
595 |
if (ddmmss.length > 1)//Minutes |
|
596 |
{ |
|
597 |
//check if the string is not empty |
|
598 |
if (ddmmss[1] != "") { mm = Integer.valueOf(ddmmss[1]); } |
|
599 |
} |
|
600 |
if (ddmmss.length > 2) {//Seconds{ |
|
601 |
//check if the string is not empty |
|
602 |
if (ddmmss[2] != "") { |
|
603 |
ss = Integer.valueOf(ddmmss[2]); |
|
604 |
} |
|
605 |
} |
|
606 |
if (decimalBit.length > 1) { //DecimalSeconds |
|
607 |
//check if the string is not empty |
|
608 |
if (decimalBit[1] != "") { |
|
609 |
sss = Double.valueOf(decimalBit[1]) / Math.pow(10, (decimalBit[1].length())); |
|
610 |
} |
|
611 |
} |
|
612 |
|
|
613 |
checkDegreeRange(dd, results); |
|
614 |
checkMinuteRange(mm, results); |
|
615 |
checkSecondRange(ss, results); |
|
616 |
|
|
617 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
618 |
|
|
619 |
}else if (pattern.description.equals("Custom variation of DD.DDD")){ |
|
620 |
|
|
621 |
//Sets pattern machted, successful, pattern type and pattern info |
|
622 |
initializeResult(results, pattern); |
|
623 |
|
|
624 |
|
|
625 |
//get sign |
|
626 |
sign = getCustomSign(str); |
|
627 |
|
|
628 |
//TODO still needs to be adapted to custom pattern |
|
629 |
results.isLongitude = getIsLongitude(str); |
|
630 |
|
|
631 |
|
|
632 |
//Remove all the unwanted stuff |
|
633 |
//Note: This method also replaces the symbols with ":" |
|
634 |
//Note: In certain cases it may make the coord unparsable |
|
635 |
str = removeCustomPatternParts(str); |
|
636 |
|
|
637 |
str = removeWhiteSpace(str); |
|
638 |
|
|
639 |
//Replace comma or dot with a current decimal separator |
|
640 |
str = fixDecimalSeparator(str); |
|
641 |
|
|
642 |
//remove the ":" here as it is not needed here for decimal degrees |
|
643 |
str = str.replace(":", ""); |
|
644 |
|
|
645 |
try { |
|
646 |
//Since this is already a decimal degree no spliting is needed |
|
647 |
dd = Double.valueOf(str); |
|
648 |
} catch (Exception e) { |
|
649 |
results.conversionSuccessful = false; |
|
650 |
results.convertedCoord = 99999; //this is to mark an error... |
|
651 |
results.conversionComments = |
|
652 |
"It looks like the supplied pattern has some ambiguous elements and the parser was unable to parse the coordinate." + |
|
653 |
"<br/>If the supplied symbols used for marking degrees, minutes or seconds contain hemisphere indicators, " + |
|
654 |
"the parser is likely to fail or yield rubbish results even though the pattern itself has been recognised." |
|
655 |
; |
|
656 |
|
|
657 |
//exit method |
|
658 |
return results; |
|
659 |
} |
|
660 |
|
|
661 |
//Since this is already a decimal degree no spliting is needed |
|
662 |
dd = Double.valueOf(str); |
|
663 |
|
|
664 |
checkDegreeRange(dd, results); |
|
665 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
666 |
|
|
667 |
|
|
668 |
}else if (pattern.description.equals("Custom variation of DD:MM.MMM")){ |
|
669 |
//-------------Customs patterns start here------------- |
|
670 |
|
|
671 |
//Sets pattern machted, successful, pattern type and pattern info |
|
672 |
initializeResult(results, pattern); |
|
673 |
|
|
674 |
//get sign |
|
675 |
sign = getCustomSign(str); |
|
676 |
|
|
677 |
//TODO still needs to be adapted to custom pattern |
|
678 |
results.isLongitude = getIsLongitude(str); |
|
679 |
|
|
680 |
|
|
681 |
|
|
682 |
//Remove all the unwanted stuff |
|
683 |
//Note: This method also replaces the symbols with ":" |
|
684 |
//Note: In certain cases it may make the coord unparsable |
|
685 |
str = removeCustomPatternParts(str); |
|
686 |
|
|
687 |
str = removeWhiteSpace(str); |
|
688 |
|
|
689 |
//Replace comma or dot with a current decimal separator |
|
690 |
str = fixDecimalSeparator(str); |
|
691 |
|
|
692 |
|
|
693 |
//Extract decimal part |
|
694 |
decimalBit = str.split(decSeparatorRegEx); |
|
695 |
|
|
696 |
//split degrees and minutes |
|
697 |
ddmm = decimalBit[0].split(":"); |
|
698 |
|
|
699 |
|
|
700 |
try { |
|
701 |
//extract values from the strings |
|
702 |
dd = Integer.valueOf(ddmm[0]); //Degrees |
|
703 |
|
|
704 |
if (ddmm.length > 1){//Minutes |
|
705 |
//check if the string is not empty |
|
706 |
if (ddmm[1] != "") { mm = Integer.valueOf(ddmm[1]); } |
|
707 |
} |
|
708 |
|
|
709 |
if (decimalBit.length > 1){//DecimalSeconds |
|
710 |
//check if the string is not empty |
|
711 |
if (decimalBit[1] != ""){ |
|
712 |
//replace the ":" if any (may be here as a result of custom symbol replacement |
|
713 |
decimalBit[1] = decimalBit[1].replace(":", ""); |
|
714 |
|
|
715 |
mmm = Double.valueOf(decimalBit[1]) / Math.pow(10, (decimalBit[1].length())); |
|
716 |
} |
|
717 |
} |
|
718 |
} catch (Exception e){ |
|
719 |
results.conversionSuccessful = false; |
|
720 |
results.convertedCoord = 99999; //this is to mark an error... |
|
721 |
results.conversionComments = |
|
722 |
"It looks like the supplied pattern has some ambiguous elements and the parser was unable to parse the coordinate." + |
|
723 |
"<br/>If the supplied symbols used for marking degrees, minutes or seconds contain hemisphere indicators, " + |
|
724 |
"the parser is likely to fail or yield rubbish results even though the pattern itself has been recognised." |
|
725 |
; |
|
726 |
|
|
727 |
//exit method |
|
728 |
return results; |
|
729 |
} |
|
730 |
|
|
731 |
|
|
732 |
checkDegreeRange(dd, results); |
|
733 |
checkMinuteRange(mm, results); |
|
734 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
735 |
|
|
736 |
} else if (pattern.description.equals("Custom variation of DD:MM:SS.SSS")){ |
|
737 |
|
|
738 |
//Sets pattern machted, successful, pattern type and pattern info |
|
739 |
initializeResult(results, pattern); |
|
740 |
|
|
741 |
|
|
742 |
//get sign |
|
743 |
sign = getCustomSign(str); |
|
744 |
|
|
745 |
//TODO still needs to be adapted to custom pattern |
|
746 |
results.isLongitude = getIsLongitude(str); |
|
747 |
|
|
748 |
|
|
749 |
//Remove all the unwanted stuff |
|
750 |
//Note: This method also replaces the symbols with ":" |
|
751 |
//Note: In certain cases it may make the coord unparsable |
|
752 |
str = removeCustomPatternParts(str); |
|
753 |
|
|
754 |
str = removeWhiteSpace(str); |
|
755 |
|
|
756 |
//Replace comma or dot with a current decimal separator |
|
757 |
str = fixDecimalSeparator(str); |
|
758 |
|
|
759 |
|
|
760 |
//Extract decimal part |
|
761 |
decimalBit = str.split(decSeparatorRegEx); |
|
762 |
|
|
763 |
//split degrees and minutes |
|
764 |
ddmmss = decimalBit[0].split(":"); |
|
765 |
|
|
766 |
|
|
767 |
try { |
|
768 |
|
|
769 |
//extract values from the strings |
|
770 |
dd = Integer.valueOf(ddmmss[0]); //Degrees |
|
771 |
if (ddmmss.length > 1) {//Minutes |
|
772 |
//check if the string is not empty |
|
773 |
if (ddmmss[1] != "") { |
|
774 |
mm = Integer.valueOf(ddmmss[1]); |
|
775 |
} |
|
776 |
} |
|
777 |
if (ddmmss.length > 2){ //Seconds |
|
778 |
//check if the string is not empty |
|
779 |
if (ddmmss[2] != "") { |
|
780 |
ss = Integer.valueOf(ddmmss[2]); |
|
781 |
} |
|
782 |
} |
|
783 |
if (decimalBit.length > 1){ //DecimalSeconds |
|
784 |
//check if the string is not empty |
|
785 |
if (decimalBit[1] != "") { |
|
786 |
sss = Double.valueOf(decimalBit[1]) / Math.pow(10, (decimalBit[1].length())); |
|
787 |
} |
|
788 |
} |
|
789 |
} catch (Exception e) { |
|
790 |
results.conversionSuccessful = false; |
|
791 |
results.convertedCoord = 99999; //this is to mark an error... |
|
792 |
results.conversionComments = |
|
793 |
"It looks like the supplied pattern has some ambiguous elements and the parser was unable to parse the coordinate." + |
|
794 |
"<br/>If the supplied symbols used for marking degrees, minutes or seconds contain hemisphere indicators, " + |
|
795 |
"the parser is likely to fail or yield rubbish results even though the pattern itself has been recognised." |
|
796 |
; |
|
797 |
|
|
798 |
//exit method |
|
799 |
return results; |
|
800 |
} |
|
801 |
|
|
802 |
|
|
803 |
checkDegreeRange(dd, results); |
|
804 |
checkMinuteRange(mm, results); |
|
805 |
checkSecondRange(ss, results); |
|
806 |
|
|
807 |
doConvertWithCheck(sign, dd, mm, mmm, ss, sss, results); |
|
808 |
|
|
809 |
}else { //default : pattern not recognized |
|
810 |
results.patternRecognised = false; |
|
811 |
results.patternType = pattern.description; |
|
812 |
results.patternMatched = pattern.pattern; |
|
813 |
|
|
814 |
results.conversionSuccessful = false; |
|
815 |
results.convertedCoord = 99999; //this is to mark an error... |
|
816 |
|
|
817 |
results.conversionComments = "Coordinate pattern not recognised!"; |
|
818 |
|
|
819 |
} |
|
820 |
|
|
821 |
//do the self check here |
|
822 |
results = selfTest(results); |
|
823 |
|
|
824 |
//return conversion results |
|
825 |
return results; |
|
826 |
} |
|
827 |
|
|
828 |
|
|
829 |
/** |
|
830 |
* @param sign |
|
831 |
* @param dd |
|
832 |
* @param mm |
|
833 |
* @param ss |
|
834 |
* @param sss |
|
835 |
* @param results |
|
836 |
*/ |
|
837 |
private void doConvertWithCheck(int sign, double dd, double mm, double mmm, double ss, double sss, ConversionResults results) { |
|
838 |
double dec; |
|
839 |
//Do the conversion if everything ok |
|
840 |
if (results.conversionSuccessful){ |
|
841 |
results.conversionComments = "Conversion successful."; |
|
842 |
|
|
843 |
dec = sign * (dd + (mm + mmm) / 60 + (ss + sss) / 3600); |
|
844 |
|
|
845 |
//one more check to ensure a coord does not exceed 180 |
|
846 |
if (dec > 180 | dec < -180){ |
|
847 |
results.conversionSuccessful = false; |
|
848 |
results.convertedCoord = 99999; //this is to mark an error... |
|
849 |
results.conversionComments += "Coordinate is either > 180 or < -180; "; |
|
850 |
} else { |
|
851 |
results.convertedCoord = dec; |
|
852 |
|
|
853 |
results.conversionComments = "Conversion successful."; |
|
854 |
|
|
855 |
//Check whether the coordinate exceeds +/- 90 and mark it in comments |
|
856 |
|
|
857 |
if (dec <= 90 && dec >= -90 && (results.isLongitude == null || results.isLongitude == false) ) { |
|
858 |
results.canBeLat = true; |
|
859 |
}else{ |
|
860 |
results.isLongitude = true; |
|
861 |
} |
|
862 |
} |
|
863 |
} |
|
864 |
} |
|
865 |
|
|
866 |
|
|
867 |
/** |
|
868 |
* @param ss |
|
869 |
* @param results |
|
870 |
*/ |
|
871 |
private void checkSecondRange(double ss, ConversionResults results) { |
|
872 |
if (ss > 59) {//seconds |
|
873 |
results.conversionSuccessful = false; |
|
874 |
results.convertedCoord = 99999; //this is to mark an error... |
|
875 |
results.conversionComments += "Seconds fall outside the range: MM >= 60; "; |
|
876 |
} |
|
877 |
} |
|
878 |
|
|
879 |
|
|
880 |
/** |
|
881 |
* @param mm |
|
882 |
* @param results |
|
883 |
*/ |
|
884 |
private void checkMinuteRange(double mm, ConversionResults results) { |
|
885 |
if (mm > 59) {//minutes |
|
886 |
results.conversionSuccessful = false; |
|
887 |
results.convertedCoord = 99999; //this is to mark an error... |
|
888 |
results.conversionComments += "Minutes fall outside the range: MM > 59; "; |
|
889 |
} |
|
890 |
} |
|
891 |
|
|
892 |
|
|
893 |
/** |
|
894 |
* @param dd |
|
895 |
* @param results |
|
896 |
*/ |
|
897 |
private void checkDegreeRange(double dd, ConversionResults results) { |
|
898 |
//do some additional checking if the coords fall into the range |
|
899 |
if (dd < -180 | dd > 180){ //degree may require another param specifying whether it's lat or lon... |
|
900 |
results.conversionSuccessful = false; |
|
901 |
results.convertedCoord = 99999; //this is to mark an error... |
|
902 |
results.conversionComments += "Degrees fall outside the range: DD < -180 | DD > 180; "; |
|
903 |
} |
|
904 |
} |
|
905 |
|
|
906 |
|
|
907 |
/** |
|
908 |
* @param str |
|
909 |
* @return |
|
910 |
*/ |
|
911 |
private Boolean getIsLongitude(String str) { |
|
912 |
//This regex checks for the negative hemisphere indicator |
|
913 |
Pattern regexLatitudeNonAmbigous = Pattern.compile("(N|n)"); |
|
914 |
Pattern regexLatitudeAmbigous = Pattern.compile("(S|s)"); |
|
915 |
|
|
916 |
//This regex checks if there weren't any other hemisphere indicators |
|
917 |
//it is needed for the specific case of the DDdMMmSSs S |
|
918 |
//so it needs to be ensured there where no positive indicators |
|
919 |
Pattern regexLongitude = Pattern.compile("(W|w|E|e)"); |
|
920 |
|
|
921 |
//if a positive indicator is found no need to search further |
|
922 |
if (regexLongitude.matcher(str).find()){ |
|
923 |
return true; |
|
924 |
}else if (regexLatitudeNonAmbigous.matcher(str).find()){ |
|
925 |
return false; |
|
926 |
}else if (regexLatitudeAmbigous.matcher(str).find()){ |
|
927 |
Pattern regexLiteralUnits = Pattern.compile("(D|d|M|m)"); |
|
928 |
|
|
929 |
//if there are no other literal units we assume that S is a |
|
930 |
//direction and not a second indicator |
|
931 |
if (! regexLiteralUnits.matcher(str).find()){ |
|
932 |
return false; |
|
933 |
}else if (regexLatitudeAmbigous.matcher(str).groupCount() > 1){ |
|
934 |
return false; |
|
935 |
}else{ |
|
936 |
return null; |
|
937 |
} |
|
938 |
}else{ |
|
939 |
return null; |
|
940 |
} |
|
941 |
} |
|
942 |
|
|
943 |
|
|
944 |
/** |
|
945 |
* Sets pattern machted, successful, pattern type and pattern info |
|
946 |
* @param results |
|
947 |
* @param pattern |
|
948 |
*/ |
|
949 |
private void initializeResult(ConversionResults results, |
|
950 |
CoordinatePattern pattern) { |
|
951 |
//Pattern matched |
|
952 |
results.patternRecognised = true; |
|
953 |
|
|
954 |
//Matching pattern succeeded so intialy the parsing is ok |
|
955 |
results.conversionSuccessful = true; |
|
956 |
|
|
957 |
//pattern info |
|
958 |
results.patternType = pattern.description; |
|
959 |
results.patternMatched = pattern.pattern; |
|
960 |
} |
|
961 |
|
|
962 |
|
|
963 |
private ConversionResults selfTest(ConversionResults results){ |
|
964 |
|
|
965 |
ConversionResults newresults = results; |
|
966 |
|
|
967 |
if (results.conversionSuccessful != false){ |
|
968 |
int sign = 1; |
|
969 |
if (Math.signum(results.convertedCoord) < 0) { |
|
970 |
sign = -1; |
|
971 |
} |
|
972 |
|
|
973 |
double decimalDegrees = sign * results.convertedCoord; |
|
974 |
int fullDegrees; |
|
975 |
|
|
976 |
double decimalMinutes; |
|
977 |
int fullMinutes; |
|
978 |
|
|
979 |
double decimalSeconds; |
|
980 |
int fullSeconds; |
|
981 |
|
|
982 |
//Get full degrees |
|
983 |
fullDegrees = (int)Math.floor(decimalDegrees); |
|
984 |
|
|
985 |
//get minutes |
|
986 |
decimalMinutes = (decimalDegrees - fullDegrees) * 60; |
|
987 |
fullMinutes = (int)Math.floor(decimalMinutes); |
|
988 |
|
|
989 |
decimalSeconds = (decimalMinutes - fullMinutes) * 60; |
|
990 |
fullSeconds = (int)Math.floor(decimalSeconds); |
|
991 |
|
|
992 |
//save the test results |
|
993 |
newresults.dd = fullDegrees; |
|
994 |
newresults.mm = fullMinutes; |
|
995 |
newresults.mmm = decimalSeconds; |
|
996 |
newresults.ss = fullSeconds; |
|
997 |
newresults.sss = decimalSeconds; |
|
998 |
|
|
999 |
} |
|
1000 |
|
|
1001 |
return newresults; |
|
1002 |
|
|
1003 |
} |
|
1004 |
|
|
1005 |
|
|
1006 |
|
|
1007 |
//------------ CUSTOM PATTERN BUILDER-------------- |
|
1008 |
|
|
1009 |
public class CustomPatternIn { |
|
1010 |
public String north; |
|
1011 |
public String south; |
|
1012 |
public String east; |
|
1013 |
public String west; |
|
1014 |
|
|
1015 |
public String degreeSymbol; |
|
1016 |
public String minuteSymbol; |
|
1017 |
public String secondSymbol; |
|
1018 |
|
|
1019 |
public boolean caseInsensitive; |
|
1020 |
public boolean allowWhiteSpace; |
|
1021 |
public boolean priorityOverDefaultPatterns; |
|
1022 |
public boolean disableDefaultPatterns; |
|
1023 |
|
|
1024 |
} |
|
1025 |
|
|
1026 |
|
|
1027 |
private class CustomPattern{ |
|
1028 |
|
|
1029 |
public List<CustomHemisphereIndicator> hemisphereIndicators; |
|
1030 |
|
|
1031 |
public String degreeSymbol; |
|
1032 |
public String minuteSymbol; |
|
1033 |
public String secondSymbol; |
|
1034 |
|
|
1035 |
public boolean caseInsensitive; |
|
1036 |
|
|
1037 |
} |
|
1038 |
|
|
1039 |
//global variable to be used if a custom pattern is used |
|
1040 |
private CustomPattern customPtrn; |
|
1041 |
|
|
1042 |
//escape some of the chars |
|
1043 |
private String escapeChars(String str){ |
|
1044 |
// backslash - first so it is not messed when other escape chars are corrected for being used in a string |
|
1045 |
str = str.replace("\\", "\\\\"); |
|
1046 |
|
|
1047 |
//dot and comma |
|
1048 |
str = str.replace(".", "\\."); |
|
1049 |
str = str.replace(",", "\\,"); |
|
1050 |
|
|
1051 |
//brackets |
|
1052 |
str = str.replace("(", "\\("); |
|
1053 |
str = str.replace(")", "\\)"); |
|
1054 |
str = str.replace("[", "\\["); |
|
1055 |
str = str.replace("]", "\\]"); |
|
1056 |
str = str.replace("{", "\\{"); |
|
1057 |
str = str.replace("}", "\\}"); |
|
1058 |
|
|
1059 |
//other replacements |
|
1060 |
str = str.replace("^", "\\^"); |
|
1061 |
str = str.replace("$", "\\$"); |
|
1062 |
str = str.replace("+", "\\+"); |
|
1063 |
str = str.replace("*", "\\*"); |
|
1064 |
str = str.replace("?", "\\?"); |
|
1065 |
str = str.replace("|", "\\|"); |
|
1066 |
|
|
1067 |
return str; |
|
1068 |
} |
|
1069 |
|
|
1070 |
|
|
1071 |
//this implements sorting by using system.Icomparable - sorting is needed later when replacing |
|
1072 |
private class CustomHemisphereIndicator implements Comparable<CustomHemisphereIndicator> { |
|
1073 |
//private variables |
|
1074 |
private int m_length; |
|
1075 |
private String m_name; |
|
1076 |
private String m_indicator; |
|
1077 |
private boolean m_positive; |
|
1078 |
|
|
1079 |
//constructor |
|
1080 |
public CustomHemisphereIndicator(String name, String indicator, int length, boolean positive){ |
|
1081 |
this.m_name = name; |
|
1082 |
this.m_indicator = indicator; |
|
1083 |
this.m_length = length; |
|
1084 |
this.m_positive = positive; |
|
1085 |
} |
|
1086 |
|
|
1087 |
//properties |
|
1088 |
|
|
1089 |
public String getName(){ |
|
1090 |
return this.m_name; |
|
1091 |
} |
|
1092 |
public void setName(String value){ |
|
1093 |
this.m_name = value; |
|
1094 |
} |
|
1095 |
|
|
1096 |
public String getIndicator(){ |
|
1097 |
return this.m_indicator; |
|
1098 |
} |
|
1099 |
public void setIndicator(String value){ |
|
1100 |
this.m_indicator = value; |
|
1101 |
} |
|
1102 |
|
|
1103 |
public int getLength(){ |
|
1104 |
return this.m_length; |
|
1105 |
} |
|
1106 |
public void setLength(int value){ |
|
1107 |
this.m_length = value; |
|
1108 |
} |
|
1109 |
|
|
1110 |
|
|
1111 |
public boolean getPositive(){ |
|
1112 |
return this.m_positive; |
|
1113 |
} |
|
1114 |
public void setPositive(boolean value){ |
|
1115 |
this.m_positive = value; |
|
1116 |
} |
|
1117 |
|
|
1118 |
/* Less than zero if this instance is less than obj. |
|
1119 |
* Zero if this instance is equal to obj. |
|
1120 |
* Greater than zero if this instance is greater than obj. |
|
1121 |
* |
|
1122 |
* This method uses the predefined method Int32.CompareTo |
|
1123 |
* */ |
|
1124 |
|
|
1125 |
public int compareTo(CustomHemisphereIndicator ind){ |
|
1126 |
|
|
1127 |
//no need to rewrite the code again, we have Integer.compareTo ready to use |
|
1128 |
return Integer.valueOf(this.getLength()).compareTo(Integer.valueOf(ind.getLength())); |
|
1129 |
} |
|
1130 |
} |
|
1131 |
|
|
1132 |
|
|
1133 |
|
|
1134 |
//This adds custom pattern to a list of already predefined patterns |
|
1135 |
//useful for batch conversions - allows for totally mixed input data (predefined & custom) |
|
1136 |
public void addCustomPattern(CustomPatternIn patternIn){ |
|
1137 |
|
|
1138 |
//new custom pattern object - to pass the needed data farther |
|
1139 |
CustomPattern pattern = new CustomPattern(); |
|
1140 |
|
|
1141 |
//keep indicators for parsing |
|
1142 |
List<CustomHemisphereIndicator> indicators = new ArrayList<CustomHemisphereIndicator>(); |
|
1143 |
|
|
1144 |
//north |
|
1145 |
CustomHemisphereIndicator ind = new CustomHemisphereIndicator("North", patternIn.north, patternIn.north.length() ,true); |
|
1146 |
indicators.add(ind); |
|
1147 |
|
|
1148 |
//south |
|
1149 |
ind = new CustomHemisphereIndicator("South", patternIn.south, patternIn.south.length(), false); |
|
1150 |
indicators.add(ind); |
|
1151 |
|
|
1152 |
//east |
|
1153 |
ind = new CustomHemisphereIndicator("East", patternIn.east, patternIn.east.length(), true); |
|
1154 |
indicators.add(ind); |
|
1155 |
|
|
1156 |
//west |
|
1157 |
ind = new CustomHemisphereIndicator("West", patternIn.west, patternIn.west.length(), false); |
|
1158 |
indicators.add(ind); |
|
1159 |
|
|
1160 |
//sort the arraylist |
|
1161 |
Collections.sort(indicators, lengthComparator); |
|
1162 |
|
|
1163 |
|
|
1164 |
//add it to the pattern object |
|
1165 |
pattern.hemisphereIndicators = indicators; |
|
1166 |
|
|
1167 |
//case insensitive |
|
1168 |
pattern.caseInsensitive = patternIn.caseInsensitive; |
|
1169 |
|
|
1170 |
//keep symbols for parsing |
|
1171 |
pattern.degreeSymbol = patternIn.degreeSymbol; |
|
1172 |
pattern.minuteSymbol = patternIn.minuteSymbol; |
|
1173 |
pattern.secondSymbol = patternIn.secondSymbol; |
|
1174 |
|
|
1175 |
|
|
1176 |
//save the data |
|
1177 |
customPtrn = pattern; |
|
1178 |
|
|
1179 |
|
|
1180 |
//----------------build custom patterns---------------- |
|
1181 |
|
|
1182 |
//prepare hemisphere indicators |
|
1183 |
String north = escapeChars(patternIn.north); |
|
1184 |
String south = escapeChars(patternIn.south); |
|
1185 |
String east = escapeChars(patternIn.east); |
|
1186 |
String west = escapeChars(patternIn.west); |
|
1187 |
|
|
1188 |
//prepare symbols |
|
1189 |
String degreesymbol = ""; |
|
1190 |
if (patternIn.degreeSymbol != ""){ |
|
1191 |
degreesymbol = "(" + escapeChars(patternIn.degreeSymbol) + ")?"; |
|
1192 |
} |
|
1193 |
|
|
1194 |
String minutesymbol = ""; |
|
1195 |
if (patternIn.minuteSymbol != ""){ |
|
1196 |
minutesymbol = "(" + escapeChars(patternIn.minuteSymbol) + ")?"; |
|
1197 |
} |
|
1198 |
|
|
1199 |
String secondsymbol = ""; |
|
1200 |
if (escapeChars(patternIn.secondSymbol) != ""){ |
|
1201 |
secondsymbol = "(" + escapeChars(patternIn.secondSymbol) + ")?"; |
|
1202 |
} |
|
1203 |
|
|
1204 |
|
|
1205 |
//is the pattern to be case insensitive? |
|
1206 |
String CaseInsensitive = ""; |
|
1207 |
if (patternIn.caseInsensitive){ |
|
1208 |
CaseInsensitive = "(?i)"; |
|
1209 |
} |
|
1210 |
|
|
1211 |
//allow whitespace |
|
1212 |
String WhiteSpace = ""; |
|
1213 |
if (patternIn.allowWhiteSpace == true){ |
|
1214 |
WhiteSpace = "(\\s)*"; |
|
1215 |
} |
|
1216 |
|
|
1217 |
//hemisphere indicator |
|
1218 |
String HemisphereIndicator = ""; |
|
1219 |
|
|
1220 |
//add north if present |
|
1221 |
if (north == ""){ |
|
1222 |
HemisphereIndicator += south; |
|
1223 |
}else{ |
|
1224 |
HemisphereIndicator += north; |
|
1225 |
if (south != ""){ |
|
1226 |
HemisphereIndicator += "|" + south; |
|
1227 |
} |
|
1228 |
} |
|
1229 |
|
|
1230 |
//add east |
|
1231 |
if (north == "" & south == ""){ |
|
1232 |
HemisphereIndicator += east; |
|
1233 |
} else { |
|
1234 |
if (east != ""){ |
|
1235 |
HemisphereIndicator += "|" + east; |
|
1236 |
} |
|
1237 |
} |
|
1238 |
|
|
1239 |
//add west |
|
1240 |
if (north == "" & south == "" & east == ""){ |
|
1241 |
HemisphereIndicator += west; |
|
1242 |
} else { |
|
1243 |
if (west != "") { |
|
1244 |
HemisphereIndicator += "|" + west; |
|
1245 |
} |
|
1246 |
} |
|
1247 |
|
|
1248 |
//add remaining bits if not empty |
|
1249 |
if (HemisphereIndicator != "") { |
|
1250 |
HemisphereIndicator = "(" + HemisphereIndicator + ")?"; |
|
1251 |
} |
|
1252 |
|
|
1253 |
List<CoordinatePattern> customPatterns = new ArrayList<CoordinatePattern>(); |
|
1254 |
|
|
1255 |
//create custom patterns based on the specified user's input |
|
1256 |
CoordinatePattern ptrn; |
|
1257 |
|
|
1258 |
//Custom variation of DD.DDD |
|
1259 |
ptrn = new CoordinatePattern(); |
|
1260 |
ptrn.description = "Custom variation of DD.DDD"; |
|
1261 |
ptrn.pattern = |
|
1262 |
CaseInsensitive + "(^" + |
|
1263 |
WhiteSpace + HemisphereIndicator + WhiteSpace + |
|
1264 |
"(" + |
|
1265 |
"(\\d{1,3}(\\.|\\,)?" + WhiteSpace + degreesymbol + WhiteSpace + "$)|(\\d{1,3}(\\.|\\,)\\d+" + WhiteSpace + degreesymbol + WhiteSpace + "$)" + |
|
1266 |
")" + |
|
1267 |
"|(^" + WhiteSpace + |
|
1268 |
"(" + |
|
1269 |
"(\\d{1,3}(\\.|\\,)?" + WhiteSpace + degreesymbol + WhiteSpace + ")|(\\d{1,3}(\\.|\\,)\\d+" + WhiteSpace + degreesymbol + WhiteSpace + ")" + |
|
1270 |
")" + |
|
1271 |
HemisphereIndicator + WhiteSpace + "$" + |
|
1272 |
"))" |
|
1273 |
; |
|
1274 |
customPatterns.add(ptrn); |
|
1275 |
|
|
1276 |
//Custom variation of DD:MM.MMM |
|
1277 |
ptrn = new CoordinatePattern(); |
|
1278 |
ptrn.description = "Custom variation of DD:MM.MMM"; |
|
1279 |
ptrn.pattern = |
|
1280 |
CaseInsensitive + "(^" + |
|
1281 |
WhiteSpace + HemisphereIndicator + WhiteSpace + |
|
1282 |
"(" + |
|
1283 |
"(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "$)|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)?" + WhiteSpace + minutesymbol + WhiteSpace + "$)|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)\\d+" + WhiteSpace + minutesymbol + WhiteSpace + "$)" + |
|
1284 |
")" + |
|
1285 |
"|(^" + WhiteSpace + |
|
1286 |
"(" + |
|
1287 |
"(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + ")|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)?" + WhiteSpace + minutesymbol + WhiteSpace + ")|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)\\d+" + WhiteSpace + minutesymbol + WhiteSpace + ")" + |
|
1288 |
")" + |
|
1289 |
HemisphereIndicator + WhiteSpace + "$" + |
|
1290 |
"))" |
|
1291 |
; |
|
1292 |
customPatterns.add(ptrn); |
|
1293 |
|
|
1294 |
//Custom variation of DD:MM:SS.SSS |
|
1295 |
ptrn = new CoordinatePattern(); |
|
1296 |
ptrn.description = "Custom variation of DD:MM:SS.SSS"; |
|
1297 |
ptrn.pattern = |
|
1298 |
CaseInsensitive + "(^" + |
|
1299 |
WhiteSpace + HemisphereIndicator + WhiteSpace + |
|
1300 |
"(" + |
|
1301 |
"(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "$)|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + "$)|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)?" + WhiteSpace + secondsymbol + WhiteSpace + "$)|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)\\d+" + WhiteSpace + secondsymbol + WhiteSpace + "$)" + |
|
1302 |
")" + |
|
1303 |
"|(^" + WhiteSpace + |
|
1304 |
"(" + |
|
1305 |
"(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + ")|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + ")|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)?" + WhiteSpace + secondsymbol + WhiteSpace + ")|(\\d{1,3}" + WhiteSpace + degreesymbol + WhiteSpace + "\\d{1,2}" + WhiteSpace + minutesymbol + WhiteSpace + "\\d{1,2}(\\.|\\,)\\d+" + WhiteSpace + secondsymbol + WhiteSpace + ")" + |
|
1306 |
")" + |
|
1307 |
HemisphereIndicator + WhiteSpace + "$" + |
|
1308 |
"))" |
|
1309 |
; |
|
1310 |
customPatterns.add(ptrn); |
|
1311 |
|
|
1312 |
//check if the default patterns are to be used |
|
1313 |
if (patternIn.disableDefaultPatterns) { |
|
1314 |
patterns = customPatterns; |
|
1315 |
} else { //if all patterns are to be used check which set has the matching priority |
|
1316 |
|
|
1317 |
//check if the custom patterns are to have priority over the default ones |
|
1318 |
if (patternIn.priorityOverDefaultPatterns){ |
|
1319 |
|
|
1320 |
//add default patterns to the custom patterns |
|
1321 |
for (int i = 0; i < patterns.size(); i++){ |
|
1322 |
customPatterns.add(patterns.get(i)); |
|
1323 |
} |
|
1324 |
|
|
1325 |
//swap array lists |
|
1326 |
patterns = customPatterns; |
|
1327 |
|
|
1328 |
}else{ |
|
1329 |
//add custom patterns to the default patterns |
|
1330 |
for (int i = 0; i < customPatterns.size(); i++){ |
|
1331 |
patterns.add(customPatterns.get(i)); |
|
1332 |
|
|
1333 |
} |
|
1334 |
} |
|
1335 |
} |
|
1336 |
} |
|
1337 |
|
|
1338 |
} |
|
1 |
// $Id$ |
|
2 |
/** |
|
3 |
* Copyright (C) 2009 EDIT |
|
4 |
* European Distributed Institute of Taxonomy |
|
5 |
* http://www.e-taxonomy.eu |
|
6 |
* |
|
7 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
8 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
9 |
* |
|
10 |
* This file is an Java adaption from the orginal CoordinateConverter written by Dominik Mikiewicz |
|
11 |
* @see www.cartomatic.pl |
|
12 |
* @see http://dev.e-taxonomy.eu/svn/trunk/geo/coordinateConverter/CoordinateConverter.cs |
|
13 |
* @see http://gis.miiz.waw.pl/webapps/coordinateconverter/ |
|
14 |
*/ |
|
15 |
package eu.etaxonomy.cdm.strategy.parser.location; |
|
16 |
|
|
17 |
import java.util.ArrayList; |
|
18 |
import java.util.Collections; |
|
19 |
import java.util.Comparator; |
|
20 |
import java.util.List; |
|
21 |
import java.util.regex.Pattern; |
|
22 |
|
|
23 |
import org.apache.log4j.Logger; |
|
24 |
|
|
25 |
/** |
|
26 |
* @author a.mueller |
|
27 |
* @date 07.06.2010 |
|
28 |
* |
|
29 |
*/ |
|
30 |
public class CoordinateConverter { |
|
31 |
@SuppressWarnings("unused") |
|
32 |
private static final Logger logger = Logger.getLogger(CoordinateConverter.class); |
|
33 |
|
|
34 |
//Patterns |
|
35 |
private List<CoordinatePattern> patterns; |
|
36 |
|
|
37 |
private static String minuteUtf8 = "\u02B9|\u00B4|\u02CA|\u0301|\u0374"; |
|
38 |
private static String secondUtf8 = "\u02BA|\u030B|\u2033|\u00B4\u00B4"; |
|
39 |
|
|
40 |
|
|
41 |
private class CoordinatePattern{ |
|
42 |
String description; |
|
43 |
String pattern; |
|
44 |
} |
|
45 |
|
|
46 |
|
|
47 |
private Comparator<CustomHemisphereIndicator> lengthComparator = new Comparator<CustomHemisphereIndicator>(){ |
|
48 |
@Override |
|
49 |
public int compare(CustomHemisphereIndicator ind1, CustomHemisphereIndicator ind2) { |
|
50 |
return Integer.valueOf(ind1.getLength()).compareTo(ind2.getLength()); |
|
51 |
} |
|
52 |
}; |
|
53 |
|
|
54 |
//Class constructor |
|
55 |
public CoordinateConverter() { |
|
56 |
//initialise pattern array |
|
57 |
patterns = new ArrayList<CoordinatePattern>(); |
|
58 |
|
|
59 |
//temp pattern variable |
|
60 |
CoordinatePattern pattern; |
|
61 |
|
|
62 |
|
|
63 |
//variations of DD.DDD with white space characters |
|
64 |
pattern = new CoordinatePattern(); |
|
65 |
pattern.description = "Variation of DD.DDD"; |
|
66 |
pattern.pattern = |
|
67 |
//+/-/Nn/Ss/Ww/EeDD.DDDD |
|
68 |
"(^" + |
|
69 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
70 |
"((\\d{1,3}(\\.|\\,)?(\\s)*$)|(\\d{1,3}(\\.|\\,)\\d+(\\s)*$))" + |
|
71 |
")" + |
|
72 |
////DD.DDDDNn/Ss/Ww/Ee |
|
73 |
"|(^" + |
|
74 |
"(\\s)*((\\d{1,3}(\\.|\\,)?(\\s)*)|(\\d{1,3}(\\.|\\,)\\d+(\\s)*))" + |
|
75 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
76 |
")"; |
|
77 |
patterns.add(pattern); |
|
78 |
|
|
79 |
|
|
80 |
//Variations of DD(\u00B0|d)MM.MMM' with whitespace characters |
|
81 |
pattern = new CoordinatePattern(); |
|
82 |
pattern.description = "Variation of DD(\u00B0|d)MM.MMM('|m)"; |
|
83 |
pattern.pattern = |
|
84 |
"(^" + |
|
85 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
86 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*$)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)?("+ minuteUtf8 + "|'|M|m)?$)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*("+ minuteUtf8 + "|'|M|m)?(\\s)*$))" + |
|
87 |
")" + |
|
88 |
"|(^" + |
|
89 |
"(\\s)*((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)?("+ minuteUtf8 + "|'|M|m)?)|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*("+ minuteUtf8 + "|'|M|m)?(\\s)*))" + |
|
90 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
91 |
")"; |
|
92 |
patterns.add(pattern); |
|
93 |
|
|
94 |
|
|
95 |
//Variations of DD\u00B0MM'SS.SSS" with whitespace characters |
|
96 |
pattern = new CoordinatePattern(); |
|
97 |
pattern.description = "Variation of DD(\u00B0|d)MM("+ minuteUtf8 + "|m)SS.SSS("+secondUtf8+"|s)"; |
|
98 |
pattern.pattern = |
|
99 |
//+/-/Nn/Ss/Ww/EeDD\u00B0MM"+ minuteUtf8 + "SS.SSS |
|
100 |
"(^" + |
|
101 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
102 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*$)" + |
|
103 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)?(\\s)*$)" + |
|
104 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*("+secondUtf8+"|\"|''|S|s)?(\\s)*$)" + |
|
105 |
"|(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*("+secondUtf8+"|\"|''|S|s)?(\\s)*$))" + |
|
106 |
")" + |
|
107 |
//DD°MM"+ minuteUtf8 + "SS.SSSNn/Ss/Ww/Ee |
|
108 |
"|(^(\\s)*" + |
|
109 |
"((\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)?(\\s)*)|" + |
|
110 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)?(\\s)*)|" + |
|
111 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*("+secondUtf8+"|\"|''|S|s)?(\\s)*)|" + |
|
112 |
"(\\d{1,3}(\\s)*(\u00B0|\u00BA|D|d)(\\s)*\\d{1,2}(\\s)*("+ minuteUtf8 + "|'|M|m)(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*("+secondUtf8+"|\"|''|S|s)?(\\s)*))" + |
|
113 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
114 |
")"; |
|
115 |
patterns.add(pattern); |
|
116 |
|
|
117 |
|
|
118 |
//Variations of DD:MM:SS.SSS with whitespace characters |
|
119 |
pattern = new CoordinatePattern(); |
|
120 |
pattern.description = "Variation of DD:MM:SS.SSS"; |
|
121 |
pattern.pattern = |
|
122 |
// +/-/Nn/Ss/Ww/EeDD:MM:SS.SSS |
|
123 |
"(^" + |
|
124 |
"(\\s)*(\\+|-|W|w|E|e|N|n|S|s)?(\\s)*" + |
|
125 |
"((\\d{1,3}(\\s)*\\:?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*$)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*$))" + |
|
126 |
")" + |
|
127 |
//DD:MM:SS.SSSNn/Ss/Ww/Ee |
|
128 |
"|(^" + |
|
129 |
"(\\s)*((\\d{1,3}(\\s)*\\:?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)?(\\s)*)|(\\d{1,3}(\\s)*\\:(\\s)*\\d{1,2}(\\s)*\\:(\\s)*\\d{1,2}(\\.|\\,)\\d+(\\s)*))" + |
|
130 |
"(W|w|E|e|N|n|S|s)?(\\s)*$" + |
|
131 |
")"; |
|
132 |
patterns.add(pattern); |
|
133 |
|
|
134 |
} |
|
135 |
|
|
136 |
|
|
137 |
//tests if a string matches one of the defined patterns |
|
138 |
private int matchPattern(String str){ |
|
139 |
int recognised = -1; |
|
140 |
|
|
141 |
//match the string against each available patern |
|
142 |
for (int i = 0; i < patterns.size(); i++){ |
|
143 |
|
|
144 |
CoordinatePattern pattern = patterns.get(i); |
|
145 |
Pattern regEx = Pattern.compile(pattern.pattern); |
|
146 |
if (regEx.matcher(str).find()) { |
|
147 |
recognised = i; |
|
148 |
break; |
|
149 |
} |
|
150 |
|
|
151 |
} |
|
152 |
return recognised; |
Also available in: Unified diff
Allow parsing of accent acute for coordinates #5716