code: public static ResidueRangeAndLength parse(String s, AtomPositionMap map) {
  		ResidueRange rr = parse(s);
  		ResidueNumber start = rr.getStart();
  
  		String chain = rr.getChainName();
  
  		// handle special "_" chain
  		if(chain == null || chain.equals("_")) {
  			ResidueNumber first = map.getNavMap().firstKey();
  			chain = first.getChainName();
  			// Quick check for additional chains. Not guaranteed if the atoms are out of order.
  			if( ! map.getNavMap().lastKey().getChainName().equals(chain) ) {
  				logger.warn("Multiple possible chains match '_'. Using chain {}",chain);
  			}
  		}
  
  		// get a non-null start and end
  		// if it's the whole chain, choose the first and last residue numbers in the chain
  		if (start==null) {
  			start = map.getFirst(chain);
  		}
  		ResidueNumber end = rr.getEnd();
  		if (end==null) { // should happen iff start==null
  			end = map.getLast(chain);
  		}
  
  		// Replace '_'
  		start.setChainName(chain);
  		end.setChainName(chain);
  
  		// Now fix any errors and calculate the length
  		return map.trimToValidResidues(new ResidueRange(chain, start, end));
  	}
docs: Parses a residue range.
  
  The AtomPositionMap is used to calculate the length and fill in missing
  information, such as for whole chains ('A:'). Supports the special chain
  name '_' for single-chain structures.
  
  If residues are specified outside of the range given in the map,
  attempts to decrease the input range to valid values. In extreme cases
  where this process fails fails to find any valid indices, returns null.
  
  For a function which more conservatively represents the input range,
  without chain inference and error fixes, use {@link ResidueRange#parse(String)}.
  @param s
  A string of the form chain_start-end. For example: <code>A.5-100</code>.
  @return The unique ResidueRange corresponding to {@code s}.