/* * @(#) src/net/sf/ivmaidns/util/StrComparator.java -- * Class for string comparators/metrics. ** * Copyright (c) 2000 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package net.sf.ivmaidns.util; /** * Class for string comparators/metrics. ** * This comparator class overrides the default semantics of * <CODE>GComparator</CODE> class for the case when both of the * objects being compared are instances of <CODE>String</CODE> * class. This class also implements <CODE>Metricable</CODE> * interface to offer some assessment metrics for string objects. * Here, case-insensitive comparison of strings is implemented * (<CODE>GComparator</CODE> class implementation offers * case-sensitive comparison for string objects), and the metrics is * string length plus one. In the subclasses * <CODE>compare(String, String)</CODE> method should be overridden * to implement specific comparison and metrics. ** * @see CharVector ** * @version 2.0 * @author Ivan Maidanski ** * @since 1.8 */ public class StrComparator extends GComparator implements Metricable { /** * The class version unique identifier for serialization * interoperability. ** * @since 1.8 */ private static final long serialVersionUID = 2114110405911422799L; /** * An instance of this comparator. ** * This constant field is initialized with the instantiation of * exactly this comparator (hides <CODE>INSTANCE</CODE> of the * superclass). The implemented comparator orders correctly strings * ignoring letters case, other objects are ordered in the same way * as by <CODE>GComparator</CODE> exact instance; * <CODE>evaluate(Object)</CODE> method for a string here returns * its <CODE>length()</CODE> plus one, for other objects zero is * returned. ** * @see #greater(java.lang.Object, java.lang.Object) * @see #evaluate(java.lang.Object) */ public static final GComparator INSTANCE = new StrComparator(); /** * Constructs a new comparator. ** * This constructor is made <CODE>public</CODE> only to allow custom * dynamic instantiation of this class. In other cases, * <CODE>INSTANCE</CODE> should be used. ** * @see #INSTANCE */ public StrComparator() {} /** * The body of 'Greater-Than' comparator. ** * Tests whether or not the first specified object is greater than * the second one. If both arguments are of <CODE>String</CODE> * class then <CODE>(compare(objA, objB) > 0)</CODE> is returned, * else <CODE>greater(objA, objB)</CODE> of the superclass is * returned. ** * @param objA * the first compared argument (may be <CODE>null</CODE>). * @param objB * the second compared argument (may be <CODE>null</CODE>). * @return * <CODE>true</CODE> if and only if <VAR>objA</VAR> is greater than * <VAR>objB</VAR>. ** * @see #INSTANCE * @see #compare(java.lang.String, java.lang.String) */ public final boolean greater(Object objA, Object objB) { boolean isGreater; if (objA instanceof String && objB instanceof String) { isGreater = false; if (compare((String)objA, (String)objB) > 0) isGreater = true; } else isGreater = super.greater(objA, objB); return isGreater; } /** * The body of the metrics. ** * Evaluates the supplied object. If <VAR>obj</VAR> is of * <CODE>String</CODE> class then <CODE>compare(null, obj)</CODE> is * returned, else this method always returns <CODE>0</CODE>. ** * @param obj * the object (may be <CODE>null</CODE>) to evaluate. * @return * the integer result of the performed evaluation. ** * @see #INSTANCE * @see #compare(java.lang.String, java.lang.String) */ public final int evaluate(Object obj) { int value = 0; if (obj instanceof String) value = compare(null, (String)obj); return value; } /** * Compares two given strings. ** * This method returns a signed integer indicating * 'less-equal-greater' relation between the specified strings (the * absolute value of the result, in fact, is the distance between * the first found mismatch and the end of the bigger-length * string). This method should be overridden in subclasses to * implement specific string comparison rules (if not, this method * compares strings in the case-insensitive manner and the metrics * (when <CODE>strA == null</CODE>) is <CODE>length()</CODE> of * <VAR>strB</VAR> plus one). Important notes: zero is returned if * <CODE>strA == strB</CODE>; this function is always asymmetrical. ** * @param strA * the first compared string (may be <CODE>null</CODE>). * @param strB * the second compared string (may be <CODE>null</CODE>). * @return * a negative integer, zero, or a positive integer as * <VAR>strA</VAR> object is less than, equal to, or greater than * <VAR>strB</VAR> one. ** * @see #INSTANCE * @see #greater(java.lang.Object, java.lang.Object) * @see #evaluate(java.lang.Object) */ public int compare(String strA, String strB) { int lenA, lenB = 0; if (strA != strB) { lenA = 0; if (strA != null) lenA = strA.length() + 1; if (strB != null) lenB = strB.length() + 1; if ((lenB = lenA - lenB) >= 0) lenA -= lenB; if (lenA <= 0) lenB = -lenB; for (int offset = 0; --lenA > 0; offset++) { char value, temp = strB.charAt(offset); if ((value = strA.charAt(offset)) != temp) { temp = Character.toUpperCase(temp); if ((value = Character.toUpperCase(value)) != temp) { temp = Character.toLowerCase(temp); if ((value = Character.toLowerCase(value)) != temp) { if (lenB <= 0) lenB = -lenB; lenB += lenA; if (value >= temp) break; lenB = -lenB; break; } } } } } return lenB; } }