]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/load/FieldGuesser.java
Version 4, January 2008
[GpsPrune.git] / tim / prune / load / FieldGuesser.java
diff --git a/tim/prune/load/FieldGuesser.java b/tim/prune/load/FieldGuesser.java
new file mode 100644 (file)
index 0000000..032874a
--- /dev/null
@@ -0,0 +1,273 @@
+package tim.prune.load;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.data.Timestamp;
+
+/**
+ * Class to try to match data with field names,
+ * using a variety of guessing techniques
+ */
+public abstract class FieldGuesser
+{
+       /**
+        * Try to guess whether the given line is a header line or data
+        * @param inValues array of values from first non-blank line of file
+        * @return true if it looks like a header row, false if it looks like data
+        */
+       private static boolean isHeaderRow(String[] inValues)
+       {
+               // Loop over values looking for a Latitude value
+               if (inValues != null)
+               {
+                       for (int v=0; v<inValues.length; v++)
+                       {
+                               Latitude lat = new Latitude(inValues[v]);
+                               if (lat.isValid()) {return false;}
+                       }
+               }
+               // No valid Latitude value found so presume header
+               return true;
+       }
+
+
+       /**
+        * Try to guess the fields for the given values from the file
+        * @param inValues array of values from first non-blank line of file
+        * @return array of fields which hopefully match
+        */
+       public static Field[] guessFields(String[] inValues)
+       {
+               // Guess whether it's a header line or not
+               boolean isHeader = isHeaderRow(inValues);
+               // make array of Fields
+               int numFields = inValues.length;
+               Field[] fields = new Field[numFields];
+               // Loop over fields to try to guess the main ones
+               for (int f=0; f<numFields; f++)
+               {
+                       if (inValues[f] != null) {
+                               String value = inValues[f].trim();
+                               // check for latitude
+                               if (!checkArrayHasField(fields, Field.LATITUDE) && fieldLooksLikeLatitude(value, isHeader))
+                               {
+                                       fields[f] = Field.LATITUDE;
+                                       continue;
+                               }
+                               // check for longitude
+                               if (!checkArrayHasField(fields, Field.LONGITUDE) && fieldLooksLikeLongitude(value, isHeader))
+                               {
+                                       fields[f] = Field.LONGITUDE;
+                                       continue;
+                               }
+                               // check for altitude
+                               if (!checkArrayHasField(fields, Field.ALTITUDE) && fieldLooksLikeAltitude(value, isHeader))
+                               {
+                                       fields[f] = Field.ALTITUDE;
+                                       continue;
+                               }
+                               // check for waypoint name
+                               if (!checkArrayHasField(fields, Field.WAYPT_NAME) && fieldLooksLikeName(value, isHeader))
+                               {
+                                       fields[f] = Field.WAYPT_NAME;
+                                       continue;
+                               }
+                               // check for timestamp
+                               if (!checkArrayHasField(fields, Field.TIMESTAMP) && fieldLooksLikeTimestamp(value, isHeader))
+                               {
+                                       fields[f] = Field.TIMESTAMP;
+                                       continue;
+                               }
+                       }
+               }
+               // Fill in the rest of the fields using just custom fields
+               // Could try to guess other fields (waypoint type, segment) or unguessed altitude, name, but keep simple for now
+               String customPrefix = I18nManager.getText("fieldname.prefix") + " ";
+               int customFieldNum = 0;
+               for (int f=0; f<numFields; f++) {
+                       if (fields[f] == null)
+                       {
+                               // Make sure lat and long are filled in if not already
+                               if (!checkArrayHasField(fields, Field.LATITUDE)) {
+                                       fields[f] = Field.LATITUDE;
+                               }
+                               else if (!checkArrayHasField(fields, Field.LONGITUDE)) {
+                                       fields[f] = Field.LONGITUDE;
+                               }
+                               else {
+                                       customFieldNum++;
+                                       fields[f] = new Field(customPrefix + (customFieldNum));
+                               }
+                       }
+               }
+               // Do a final check to make sure lat and long are in there
+               if (!checkArrayHasField(fields, Field.LATITUDE)) {
+                       fields[0] = Field.LATITUDE;
+               }
+               else if (!checkArrayHasField(fields, Field.LONGITUDE)) {
+                       fields[1] = Field.LONGITUDE;
+               }
+               return fields;
+       }
+
+
+       /**
+        * Check whether the given field array has the specified field
+        * @param inFields
+        * @param inCheckField
+        * @return true if Field is contained within the array
+        */
+       private static boolean checkArrayHasField(Field[] inFields, Field inCheckField)
+       {
+               for (int f=0; f<inFields.length; f++)
+               {
+                       if (inFields[f] != null && inFields[f].equals(inCheckField)) {
+                               return true;
+                       }
+               }
+               // not found
+               return false;
+       }
+
+
+       /**
+        * Check whether the given String looks like a Latitude value
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be latitude
+        */
+       private static boolean fieldLooksLikeLatitude(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       // This is a header line so look for english or local text
+                       String upperValue = inValue.toUpperCase();
+                       return (upperValue.equals("LATITUDE")
+                               || upperValue.equals(I18nManager.getText("fieldname.latitude").toUpperCase()));
+               }
+               else
+               {
+                       // Note this will also catch longitudes too
+                       Latitude lat = new Latitude(inValue);
+                       return lat.isValid();
+               }
+       }
+
+       /**
+        * Check whether the given String looks like a Longitude value
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be longitude
+        */
+       private static boolean fieldLooksLikeLongitude(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       // This is a header line so look for english or local text
+                       String upperValue = inValue.toUpperCase();
+                       return (upperValue.equals("LONGITUDE")
+                               || upperValue.equals(I18nManager.getText("fieldname.longitude").toUpperCase()));
+               }
+               else
+               {
+                       // Note this will also catch latitudes too
+                       Longitude lon = new Longitude(inValue);
+                       return lon.isValid();
+               }
+       }
+
+       /**
+        * Check whether the given String looks like an Altitude value
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be altitude
+        */
+       private static boolean fieldLooksLikeAltitude(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       // This is a header line so look for english or local text
+                       String upperValue = inValue.toUpperCase();
+                       return (upperValue.equals("ALTITUDE")
+                               || upperValue.equals("ALT")
+                               || upperValue.equals(I18nManager.getText("fieldname.altitude").toUpperCase()));
+               }
+               else
+               {
+                       // Look for a number less than 100000
+                       try
+                       {
+                               int intValue = Integer.parseInt(inValue);
+                               return (intValue > 0 && intValue < 100000);
+                       }
+                       catch (NumberFormatException nfe) {}
+                       return false;
+               }
+       }
+
+
+       /**
+        * Check whether the given String looks like a waypoint name
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be a name
+        */
+       private static boolean fieldLooksLikeName(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       // This is a header line so look for english or local text
+                       String upperValue = inValue.toUpperCase();
+                       return (upperValue.equals("NAME")
+                               || upperValue.equals("LABEL")
+                               || upperValue.equals(I18nManager.getText("fieldname.waypointname").toUpperCase()));
+               }
+               else
+               {
+                       // Look for at least two letters in it
+                       int numLetters = 0;
+                       for (int i=0; i<inValue.length(); i++)
+                       {
+                               char currChar = inValue.charAt(i);
+                               if (Character.isLetter(currChar)) {
+                                       numLetters++;
+                               }
+                               // Not interested if it contains ":" or "."
+                               if (currChar == ':' || currChar == '.') {return false;}
+                       }
+                       return numLetters >= 2;
+               }
+       }
+
+       /**
+        * Check whether the given String looks like a timestamp
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be a timestamp
+        */
+       private static boolean fieldLooksLikeTimestamp(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       String upperValue = inValue.toUpperCase();
+                       // This is a header line so look for english or local text
+                       return (upperValue.equals("TIMESTAMP")
+                               || upperValue.equals("TIME")
+                               || upperValue.equals(I18nManager.getText("fieldname.timestamp").toUpperCase()));
+               }
+               else
+               {
+                       // must be at least 7 characters long
+                       if (inValue.length() < 7) {return false;}
+                       Timestamp stamp = new Timestamp(inValue);
+                       return stamp.isValid();
+               }
+       }
+}