Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 19088)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 19089)
@@ -255,4 +255,5 @@
         FACTORY_MAP.put("URL_encode", Factory.of(String.class, Functions::URL_encode));
         FACTORY_MAP.put("XML_encode", Factory.of(String.class, Functions::XML_encode));
+        FACTORY_MAP.put("siunit_length", Factory.of(String.class, Functions::siunit_length));
         FACTORY_MAP.put("abs", Factory.of(Math::acos));
         FACTORY_MAP.put("acos", Factory.of(Math::acos));
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java	(revision 19088)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java	(revision 19089)
@@ -1186,4 +1186,23 @@
 
     /**
+     * Convert a length unit to meters
+     * <p>
+     * Tries to convert a length unit to meter value or returns a - when impossible
+     * @param s arbitrary string representing a length
+     * @return the length converted to meters
+     * @since 19089
+     */
+    public static String siunit_length(String s) {
+        if (s == null)
+            return null;
+        try {
+            return Utils.unitToMeter(s).toString();
+        } catch (IllegalArgumentException e) {
+            Logging.debug(e);
+        }
+        return "-";
+    }
+
+    /**
      * Calculates the CRC32 checksum from a string (based on RFC 1952).
      * @param s the string
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 19088)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 19089)
@@ -91,4 +91,7 @@
     private static final Pattern REMOVE_DIACRITICS = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
 
+    private static final Pattern PATTERN_LENGTH = Pattern.compile("^(\\d+(?:\\.\\d+)?)(cm|mm|m|ft|in|'|\")?$");
+    private static final Pattern PATTERN_LENGTH2 = Pattern.compile("^(\\d+(?:\\.\\d+)?)(ft|')(\\d+(?:\\.\\d+)?)(in|\")?$");
+
     private static final String DEFAULT_STRIP = "\uFEFF\u200B";
 
@@ -1526,5 +1529,5 @@
      * @return byte array of data in input stream (empty if stream is null)
      * @throws IOException if any I/O error occurs
-     * @deprecated since xxx -- use {@link InputStream#readAllBytes()} instead
+     * @deprecated since 19089 -- use {@link InputStream#readAllBytes()} instead
      */
     @Deprecated
@@ -2059,3 +2062,32 @@
         return string == null ? null : string.intern();
     }
+
+    /**
+     * Convert a length unit to meters
+     * @param s arbitrary string representing a length
+     * @return the length converted to meters
+     * @since 19089
+     */
+    public static Double unitToMeter(String s) throws IllegalArgumentException {
+        s = s.replaceAll(" ", "").replaceAll(",", ".");
+        Matcher m = PATTERN_LENGTH.matcher(s);
+        if (m.matches()) {
+            Double v = Double.valueOf(m.group(1));
+            if ("cm".equals(m.group(2)))
+                v *= 0.01;
+            else if ("mm".equals(m.group(2)))
+                v *= 0.001;
+            else if ("ft".equals(m.group(2)) || "'".equals(m.group(2)))
+                v *= 0.3048;
+            else if ("in".equals(m.group(2)) || "\"".equals(m.group(2)))
+                v *= 0.0254;
+            return v;
+        } else {
+            m = PATTERN_LENGTH2.matcher(s);
+            if (m.matches()) {
+                return Double.valueOf(m.group(1))*0.3048+Double.valueOf(m.group(3))*0.0254;
+            }
+        }
+        throw new IllegalArgumentException("Invalid length value: " + s);
+    }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java	(revision 19088)
+++ /trunk/test/unit/org/openstreetmap/josm/tools/UtilsTest.java	(revision 19089)
@@ -552,3 +552,22 @@
         assertEquals(-1.0, Utils.getStandardDeviation(new double[]{0}));
     }
+
+    /**
+     * Test of {@link Utils#unitToMeter(String)}
+     */
+    @Test
+    void testUnitToMeter() {
+        assertEquals(1.2, Utils.unitToMeter("1.2"));
+        assertEquals(1.3, Utils.unitToMeter("  1,3 m "));
+        assertEquals(1.4, Utils.unitToMeter("1.4m"));
+        assertEquals(1.5, Utils.unitToMeter("150cm"));
+        assertEquals(1.6, Utils.unitToMeter("1600.0mm"));
+        assertEquals(3.048, Utils.unitToMeter("10ft"));
+        assertEquals(6.096, Utils.unitToMeter("20'"));
+        assertEquals(2.54, Utils.unitToMeter("100in"));
+        assertEquals(5.08, Utils.unitToMeter("200\""));
+        assertEquals(3.0734, Utils.unitToMeter("10ft1in"));
+        assertEquals(6.1468, Utils.unitToMeter("20'2\""));
+        assertThrows(IllegalArgumentException.class, () -> Utils.unitToMeter("Hallo"));
+    }
 }
