// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.osm; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; public class SimplePrimitiveId implements PrimitiveId, Serializable { private static final long serialVersionUID = 1L; private final long id; private final OsmPrimitiveType type; public static final Pattern ID_PATTERN = Pattern.compile("(n|node|w|way|r|rel|relation)[ /]?(\\d+)"); public static final Pattern MULTIPLE_IDS_PATTERN = Pattern.compile(ID_PATTERN.pattern() + "(-(\\d+))?"); public SimplePrimitiveId(long id, OsmPrimitiveType type) { this.id = id; this.type = type; } @Override public OsmPrimitiveType getType() { return type; } @Override public long getUniqueId() { return id; } @Override public boolean isNew() { return id <= 0; } @Override public int hashCode() { return Objects.hash(id, type); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; SimplePrimitiveId that = (SimplePrimitiveId) obj; return id == that.id && type == that.type; } @Override public String toString() { return type.toString() + ' ' + id; } /** * Parses a {@code SimplePrimitiveId} from the string {@code s}. * @param s the string to be parsed, e.g., {@code n1}, {@code node1}, * {@code w1}, {@code way1}, {@code r1}, {@code rel1}, {@code relation1}. * @return the parsed {@code SimplePrimitiveId} * @throws IllegalArgumentException if the string does not match the pattern */ public static SimplePrimitiveId fromString(String s) { final Matcher m = ID_PATTERN.matcher(s); if (m.matches()) { return new SimplePrimitiveId(Long.parseLong(m.group(m.groupCount())), getOsmPrimitiveType(s.charAt(0))); } else { throw new IllegalArgumentException("The string " + s + " does not match the pattern " + ID_PATTERN); } } /** * Parses a range {@code SimplePrimitiveId} from the string {@code s}. * @param s the string to be parsed, e.g., {@code node1}, {@code node1-7}, {@code node70-7}. * @return the parsed {@code SimplePrimitiveId}s * @throws IllegalArgumentException if the string does not match the pattern */ public static List<SimplePrimitiveId> multipleFromString(String s) { final Matcher m = MULTIPLE_IDS_PATTERN.matcher(s); if (m.matches()) { return extractIdsInto(m, new ArrayList<SimplePrimitiveId>()); } else { throw new IllegalArgumentException("The string " + s + " does not match the pattern " + MULTIPLE_IDS_PATTERN); } } /** * Attempts to parse extract any primitive id from the string {@code s}. * @param s the string to be parsed, e.g., {@code "n1, w1"}, {@code "node1 and rel2"}, {@code "node 123-29"}. * @return the parsed list of {@code OsmPrimitiveType}s. */ public static List<SimplePrimitiveId> fuzzyParse(String s) { final List<SimplePrimitiveId> ids = new ArrayList<>(); final Matcher m = MULTIPLE_IDS_PATTERN.matcher(s); while (m.find()) { extractIdsInto(m, ids); } return ids; } private static List<SimplePrimitiveId> extractIdsInto(MatchResult m, List<SimplePrimitiveId> ids) { final OsmPrimitiveType type = getOsmPrimitiveType(m.group(1).charAt(0)); final String firstId = m.group(2); final String lastId = m.group(4); if (lastId != null) { final long lastIdParsed; if (lastId.length() < firstId.length()) { // parse ranges such as 123-25 or 123-5 lastIdParsed = Long.parseLong(firstId.substring(0, firstId.length() - lastId.length()) + lastId); } else { // parse ranges such as 123-125 or 998-1001 lastIdParsed = Long.parseLong(lastId); } for (long i = Long.parseLong(firstId); i <= lastIdParsed; i++) { ids.add(new SimplePrimitiveId(i, type)); } } else { ids.add(new SimplePrimitiveId(Long.parseLong(firstId), type)); } return ids; } private static OsmPrimitiveType getOsmPrimitiveType(char firstChar) { return firstChar == 'n' ? OsmPrimitiveType.NODE : firstChar == 'w' ? OsmPrimitiveType.WAY : OsmPrimitiveType.RELATION; } }