Changeset 14508 in josm


Ignore:
Timestamp:
2018-12-04T08:08:46+01:00 (4 months ago)
Author:
GerdP
Message:

see #17055 improve TagChecker

  • allow Levenshtein distance of 2 so that residentail is found as typo
  • disable Fix for typos where the correct value is not known, e.g. services can be service or services
  • don't suggest values if all preset values are short, e.g.

layer=6 should not say "6 looks like one of [1,2,3,4,5]"

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java

    r14490 r14508  
    1414import java.util.Collections;
    1515import java.util.HashMap;
     16import java.util.HashSet;
    1617import java.util.List;
    1718import java.util.Locale;
     
    7778    private static final List<CheckerData> checkerData = new ArrayList<>();
    7879    private static final List<String> ignoreDataStartsWith = new ArrayList<>();
    79     private static final List<String> ignoreDataEquals = new ArrayList<>();
     80    private static final Set<String> ignoreDataEquals = new HashSet<>();
    8081    private static final List<String> ignoreDataEndsWith = new ArrayList<>();
    8182    private static final List<Tag> ignoreDataTag = new ArrayList<>();
     
    123124     */
    124125    public static final String PREF_CHECK_FIXMES_BEFORE_UPLOAD = PREF_CHECK_FIXMES + "BeforeUpload";
     126
     127    private static final int MAX_LEVENSHTEIN_DISTANCE = 2;
    125128
    126129    protected boolean checkKeys;
     
    142145
    143146    // CHECKSTYLE.OFF: SingleSpaceSeparator
    144     protected static final int EMPTY_VALUES      = 1200;
    145     protected static final int INVALID_KEY       = 1201;
    146     protected static final int INVALID_VALUE     = 1202;
    147     protected static final int FIXME             = 1203;
    148     protected static final int INVALID_SPACE     = 1204;
    149     protected static final int INVALID_KEY_SPACE = 1205;
    150     protected static final int INVALID_HTML      = 1206; /* 1207 was PAINT */
    151     protected static final int LONG_VALUE        = 1208;
    152     protected static final int LONG_KEY          = 1209;
    153     protected static final int LOW_CHAR_VALUE    = 1210;
    154     protected static final int LOW_CHAR_KEY      = 1211;
    155     protected static final int MISSPELLED_VALUE  = 1212;
    156     protected static final int MISSPELLED_KEY    = 1213;
    157     protected static final int MULTIPLE_SPACES   = 1214;
     147    protected static final int EMPTY_VALUES             = 1200;
     148    protected static final int INVALID_KEY              = 1201;
     149    protected static final int INVALID_VALUE            = 1202;
     150    protected static final int FIXME                    = 1203;
     151    protected static final int INVALID_SPACE            = 1204;
     152    protected static final int INVALID_KEY_SPACE        = 1205;
     153    protected static final int INVALID_HTML             = 1206; /* 1207 was PAINT */
     154    protected static final int LONG_VALUE               = 1208;
     155    protected static final int LONG_KEY                 = 1209;
     156    protected static final int LOW_CHAR_VALUE           = 1210;
     157    protected static final int LOW_CHAR_KEY             = 1211;
     158    protected static final int MISSPELLED_VALUE         = 1212;
     159    protected static final int MISSPELLED_KEY           = 1213;
     160    protected static final int MULTIPLE_SPACES          = 1214;
     161    protected static final int MISSPELLED_VALUE_NO_FIX  = 1215;
    158162    // CHECKSTYLE.ON: SingleSpaceSeparator
    159163    // 1250 and up is used by tagcheck
     
    388392     */
    389393    public static boolean isTagIgnored(String key, String value) {
    390         boolean tagInPresets = isTagInPresets(key, value);
    391         boolean ignore = false;
    392 
     394        if (ignoreDataEquals.contains(key)) {
     395            return true;
     396        }
    393397        for (String a : ignoreDataStartsWith) {
    394398            if (key.startsWith(a)) {
    395                 ignore = true;
    396             }
    397         }
    398         for (String a : ignoreDataEquals) {
    399             if (key.equals(a)) {
    400                 ignore = true;
     399                return true;
    401400            }
    402401        }
    403402        for (String a : ignoreDataEndsWith) {
    404403            if (key.endsWith(a)) {
    405                 ignore = true;
    406             }
    407         }
    408 
    409         if (!tagInPresets) {
     404                return true;
     405            }
     406        }
     407
     408        if (!isTagInPresets(key, value)) {
    410409            for (Tag a : ignoreDataTag) {
    411410                if (key.equals(a.getKey()) && value.equals(a.getValue())) {
    412                     ignore = true;
     411                    return true;
    413412                }
    414413            }
    415414        }
    416         return ignore;
     415        return false;
    417416    }
    418417
     
    535534                    // try to fix common typos and check again if value is still unknown
    536535                    String fixedValue = harmonizeValue(prop.getValue());
    537                     Map<String, String> possibleValues = getPossibleValues(getPresetValues(key));
     536                    Set<String> possibleValues = getPresetValues(key);
    538537                    List<String> fixVals = new ArrayList<>();
    539                     if (!possibleValues.containsKey(fixedValue)) {
    540                         int minDist = 2;
     538                    int maxPresetValueLen = 0;
     539                    if (!possibleValues.contains(fixedValue)) {
     540                        // use Levenshtein distance to find typical typos
     541                        int minDist = MAX_LEVENSHTEIN_DISTANCE + 1;
    541542                        String closest = null;
    542                         for (String possibleVal : possibleValues.keySet()) {
     543                        for (String possibleVal : possibleValues) {
     544                            if (possibleVal.isEmpty())
     545                                continue;
     546                            maxPresetValueLen = Math.max(maxPresetValueLen, possibleVal.length());
    543547                            int dist = Utils.getLevenshteinDistance(possibleVal, fixedValue);
    544548                            if (dist < minDist) {
     
    551555                            }
    552556                        }
    553                         if (minDist <= 1) {
     557                        fixedValue = null;
     558                        if (minDist <= MAX_LEVENSHTEIN_DISTANCE && maxPresetValueLen > MAX_LEVENSHTEIN_DISTANCE) {
    554559                            if (fixVals.size() < 2) {
    555560                                fixedValue = closest;
     
    557562                                Collections.sort(fixVals);
    558563                                // misspelled preset value with multiple good alternatives
    559                                 errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE)
     564                                errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE_NO_FIX)
    560565                                        .message(tr("Misspelled property value"),
    561566                                                marktr("Value ''{0}'' for key ''{1}'' looks like one of {2}."), prop.getValue(), key, fixVals)
     
    567572                        }
    568573                    }
    569                     if (possibleValues.containsKey(fixedValue)) {
    570                         final String newValue = possibleValues.get(fixedValue);
     574                    if (fixedValue != null && possibleValues.contains(fixedValue)) {
     575                        final String newValue = fixedValue;
    571576                        // misspelled preset value
    572577                        errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE)
     
    603608    }
    604609
    605     private static Map<String, String> getPossibleValues(Set<String> values) {
    606         // generate a map with common typos
    607         Map<String, String> map = new HashMap<>();
    608         if (values != null) {
    609             for (String value : values) {
    610                 map.put(value, value);
    611                 if (value.contains("_")) {
    612                     map.put(value.replace("_", ""), value);
    613                 }
    614             }
    615         }
    616         return map;
    617     }
    618 
    619610    private static String harmonizeKey(String key) {
    620611        return Utils.strip(key.toLowerCase(Locale.ENGLISH).replace('-', '_').replace(':', '_').replace(' ', '_'), "-_;:,");
  • trunk/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java

    r14490 r14508  
    1616import org.openstreetmap.josm.data.osm.OsmUtils;
    1717import org.openstreetmap.josm.data.osm.Tag;
     18import org.openstreetmap.josm.data.validation.Severity;
    1819import org.openstreetmap.josm.data.validation.TestError;
    1920import org.openstreetmap.josm.testutils.JOSMTestRules;
     
    7879        assertEquals("Misspelled property key", errors.get(0).getMessage());
    7980        assertEquals("Key 'Brand' looks like 'brand'.", errors.get(0).getDescription());
     81        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
    8082        assertFalse(errors.get(0).isFixable());
    8183    }
     
    9193        assertEquals("Presets do not contain property key", errors.get(0).getMessage());
    9294        assertEquals("Key 'namez' not in presets.", errors.get(0).getDescription());
     95        assertEquals(Severity.OTHER, errors.get(0).getSeverity());
     96        assertFalse(errors.get(0).isFixable());
    9397    }
    9498
     
    103107        assertEquals("Misspelled property value", errors.get(0).getMessage());
    104108        assertEquals("Value 'forrest' for key 'landuse' looks like 'forest'.", errors.get(0).getDescription());
     109        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
     110        assertTrue(errors.get(0).isFixable());
    105111    }
    106112
     
    115121        assertEquals("Misspelled property value", errors.get(0).getMessage());
    116122        assertEquals("Value 'servics' for key 'highway' looks like one of [service, services].", errors.get(0).getDescription());
     123        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
     124        assertFalse(errors.get(0).isFixable());
     125    }
     126
     127    /**
     128     * Check for misspelled value.
     129     * @throws IOException if any I/O error occurs
     130     */
     131    @Test
     132    public void testMisspelledTag3() throws IOException {
     133        final List<TestError> errors = test(OsmUtils.createPrimitive("node highway=residentail"));
     134        assertEquals(1, errors.size());
     135        assertEquals("Misspelled property value", errors.get(0).getMessage());
     136        assertEquals("Value 'residentail' for key 'highway' looks like 'residential'.", errors.get(0).getDescription());
     137        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
     138        assertTrue(errors.get(0).isFixable());
     139    }
     140    /**
     141     * Check for misspelled value.
     142     * @throws IOException if any I/O error occurs
     143     */
     144    @Test
     145    public void testShortValNotInPreset() throws IOException {
     146        final List<TestError> errors = test(OsmUtils.createPrimitive("node layer=6"));
     147        assertEquals(1, errors.size());
     148        assertEquals("Presets do not contain property value", errors.get(0).getMessage());
     149        assertEquals("Value '6' for key 'layer' not in presets.", errors.get(0).getDescription());
     150        assertEquals(Severity.OTHER, errors.get(0).getSeverity());
     151        assertFalse(errors.get(0).isFixable());
    117152    }
    118153
Note: See TracChangeset for help on using the changeset viewer.