Mega Code Archive

 
Categories / Java / Data Type
 

Numbers will be equals if enough decimals are equals, without thinking about approximations

import java.util.ArrayList; import java.util.Collections; import java.util.List; /*  * Copyright 2007-2011 Nicolas Zozol  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ //package com.robustaweb.library.commons.util; /**  * This class is designed to simplify Numbers representation in HTML views. <p>Be aware that it's not time efficiency, not designed for complex Math</p>.  * @author Nicolas Zozol for Robusta Web ToolKit & http://www.edupassion.com - nzozol@robustaweb.com  */ public class MathUtils {     /**      *  Numbers will be equals if enough decimals are equals, without thinking about approximations. This is absolutely not a pure mathematic Equality.      * <p>      * approximativelyEquals(1.2352, 1.2357, 3) returns true because there is no rounding at the 3th decimal      * </p>      *      * @param n1 first numbre      * @param n2 second number      * @param decimalPrecision      * @return true if n1 is approximatively equal to n2      */     public static boolean approximativelyEquals(Number n1, Number n2, int decimalPrecision) {         if (n1.toString().equals(n2.toString())) {             return true;         }         String s1 = n1.toString();         String s2 = n2.toString();         s1 = StringUtils.removeTrailingCharacters(s1, '0');         s2 = StringUtils.removeTrailingCharacters(s2, '0');         if (!s1.contains(".") && !s2.contains(".")) {             return s1.equals(s2);         }         int seriousNumber;         if (s1.contains(".")) {             seriousNumber = s1.indexOf('.');         } else {//s2.contains(".")             seriousNumber = s2.indexOf('.');         }         /* checking before */         if (s1.substring(0, seriousNumber).equals(s2.substring(0, seriousNumber))) {             s1 = s1.substring(seriousNumber);             s1 = StringUtils.removeCharacter(s1, '.');             s2 = s2.substring(seriousNumber);             s2 = StringUtils.removeCharacter(s2, '.');             /* truncation */             String t1 = StringUtils.truncate(s1, decimalPrecision);             String t2 = StringUtils.truncate(s2, decimalPrecision);             t1 = StringUtils.removeTrailingCharacters(t1, '0');             t2 = StringUtils.removeTrailingCharacters(t2, '0');             return t1.equals(t2);         } else {             return false;         }     }     /**      * <p>      * Returns a visual approximation of a number, keeping only a specified decimals. <br/>      * For exemple : <br/>      *    &nbsp; approximate(12.2578887 , 2) will return 12.25 <br/>      *    &nbsp; approximate(12.25 , 0) will return 12 <br/>      *    &nbsp; approximate(12.00 , 3) will return 12 <br/>      *    &nbsp; approximate(19.5 , 0) will return 20 <br/>      *</p>      * <p>The last exemple emphasis the fact that it's made for showing convenient numbers for no mathematical public. If the number was</p>      * <p>Note that Math.round(19.5) returns 20, not 19. This function will act the same way.</p>      * @param n      * @param precision      * @return      */     public static String approximate(Number n, int precision) {         if (n instanceof Integer) {             return n.toString();         }         String s = n.toString();         if (!s.contains(".")) {             return s;         }         String serious = s.substring(0, s.indexOf('.'));         s = s.substring(s.indexOf('.') + 1);         s = StringUtils.removeTrailingCharacters(s, '0');         if (s.length() == 0) {             return serious;         }         // We'll comments results based on approximate(12.63645, 3) and approximate(12.63545, 0)         String decimals = "";         if (s.length() > precision) {             decimals = StringUtils.truncate(s, precision + 1);             //decimal is now "636" or "6"             Float after = new Float(decimals);             //after is 636 or 6, as Float objects             after = after / 10;             //after is 63.6 or .6, as Float objects             Integer round = Math.round(after);             //round is 64 or 1             decimals = round.toString();             decimals = StringUtils.removeTrailingCharacters(decimals, '0');         } else {             decimals = StringUtils.truncate(s, precision);             decimals = StringUtils.removeTrailingCharacters(decimals, '0');         }         if (decimals.length() > 0 && precision > 0) {             return serious + "." + decimals;         } else {             //if we must round the serious string             if (decimals.length() > 0 && precision == 0) {                 assert decimals.length() == 1 : "problem here !";                 if (decimals.length() != 1) {                     throw new IllegalStateException("Error in the algorithm for MathUtilisties.approximate(" + n + ", " + precision + ")");                 }                 Integer finalValue = new Integer(decimals);                 if (finalValue > 0) {                     Integer si = new Integer(serious);                     si += 1;                     return si.toString();                 } else {                     return serious;                 }             } else {                 return serious;             }         }     }     /**      * Convert a String in Double, Float, Integer, Long, Short or Byte, depending on the T exemple      * For exemple convert("2", 0f) will return 2.0 as a float      * @param <T> type returned      * @param str String to convert      * @param exemple exemple of the type      * @return a number representation of the String      * @throws IllegalArgumentException if the T type is not Double, Float, Integer, Long, Short or Byte      * @throws NumberFormatException if the conversion fails      */     public static <T extends Number> T convert(String str, T exemple) throws NumberFormatException, IllegalArgumentException{         T result = null;         if (exemple instanceof Double) {             result = (T) new Double(str);         } else if (exemple instanceof Float) {             result = (T) new Float(str);         } else if (exemple instanceof Integer) {             result = (T) new Integer(str);         } else if (exemple instanceof Long) {             result = (T) new Long(str);         } else if (exemple instanceof Short) {             result = (T) new Short(str);         } else if (exemple instanceof Byte) {             result = (T) new Byte(str);         }else{             throw new IllegalArgumentException("Conversion is not possible with class "+exemple.getClass()                     +"; only allowing Double, Float, integer, Long, Short & Byte");         }         return result;     }    } /**  * This class gives a few function to waork on Strings.  * <p>Most importants are probably <ul>  * <li>{@link StringUtils#validateEmail(String) validateEmail()}  * <li>{@link StringUtils#replaceAll(String, String, String) replaceAll()}  * <li> {@link StringUtils#removeCharacters(String, String) removeCharacters()}  * </ul>  * </p>  * @author Nicolas Zozol for Robusta Web ToolKit & http://www.edupassion.com - nzozol@robustaweb.com  * TODO : verify this class is GWT compatible  */  class StringUtils {     /**      * This function test if an email is valid. It's not the best validation of the world : all good emails will pass,      * but some wrong emails (even if it's very unlikely) may also pass.      * <p> This function is based on the Javascript pattern /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/      * </p>      * <p>Check <a href="http://www.ietf.org/rfc/rfc2822.txt">IETF</a> for more informations.</p>      * @param email email to be tested      * @return true if email is an email pattern, false if not      * @throws  IllegalArgumentException if the email is null      */     public static boolean validateEmail(String email) {         if (email == null) {             throw new IllegalArgumentException("The email is null");         }         if (email.equals("")) {             return false;         }         String worker = new String(email);         worker = worker.trim();         return worker.matches("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\\.([a-zA-Z])+([a-zA-Z])+");         /*         //Set the email pattern string         //Pattern p = Pattern.compile(".+@.+\\.[a-z]+");         Pattern p = Pattern.compile("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\\.([a-zA-Z])+([a-zA-Z])+");         //Match the given string with the pattern         Matcher m = p.matcher(worker);         return m.matches();*/     }     /**      * Returns true if the String could be a md5      * @param md5String String to test : could it be a MD5, or there is no way ?      * @return true if the String could be a md5      * @throws IllegalArgumentException if the md5String is null      */     public static boolean validateMD5(String md5String) {         if (md5String == null) {             throw new IllegalArgumentException("md5String is null");         }         return md5String.length() == 32 && md5String.matches("([a-z0-9])+");     }     /**      * <p>removes a character in the String </p>      *      * <p>      * String boss="Bruce Springsteen";<br/>      * String result = StringUtils.removeCharacter(boss, 'e') returns "Bruc Springstn".<br/>      * But the original String boss is not modified.      * </p>      * @param originalString      * @param c      * @return      */     public static String removeCharacter(String string, char c) {         String work = new String(string);         String s = "" + c;         work = work.replace(s, "");         return work;     }     /**      * <p>Removes in the string every characters inside charactersToRemove.<br/>      * For exemple removeCharacters("Napoleon","nou") returns Naple because it will remove one 'n', two 'o' and zero 'u' <br/>      * Like for removeCharacter(String string, char c), the original String is not modified.</p>      * <p>It's a recursive function, not the fastest you may have.</p>      *       * @param originalString Original string      * @param charactersToRemove characters that will be removed form the Original String      * @return a new string without the specified characters      * @throws IllegalArgumentException if original or charactersToRemove is null      */     public static String removeCharacters(String original, String charactersToRemove) {         if (original == null) {             throw new IllegalArgumentException("Your original parameter is null");         }         if (charactersToRemove == null) {             throw new IllegalArgumentException("charactersToRemove parameter si null");         }         String work = new String(original);         char c;         for (int i = 0; i < charactersToRemove.length(); i++) {             c = charactersToRemove.charAt(i);             work = removeCharacter(work, c);         }         return work;     }     /**      * Will remove all characters from the end. <br/>      * <p>      * removeStartingCharacters(iiiiMalagi, 'i') returns Malagi      * </p>      * If the string is empty, it returns also an empty string.      * If the string is null, it will throw a IllegalArgumentException      * @param originalString Original parameter      * @param character      * @throws IllegalArgumentException : if the string is null      * @return Removes all the specified character found at the beginning of the string      */     public static String removeStartingCharacters(String originalString, char character) {         if (originalString == null) {             throw new IllegalArgumentException("original String is null");         }         if (originalString.length() == 0) {             return originalString;         }         String result = new String(originalString);         while (result.indexOf(character) == 0) {             result = removeFirstCharacter(result);             if (result.length() == 0) {                 return "";             }         }         return result;     }     /**      * Will remove all characters from the end. <br/>      * <p>      * removeTrailingCharacters(Malagaaaa, 'a') returns Malag      * </p>      * If the string is empty, it returns also an empty string.      * If the string is null, it will throw a IllegalArgumentException      * @param originalString Original parameter      * @param character      * @throws IllegalArgumentException : if the string is null      * @return Removes all the specified character found at the end of the string      */     public static String removeTrailingCharacters(String originalString, char character) {         if (originalString == null) {             throw new IllegalArgumentException("original String is null");         }         if (originalString.length() == 0) {             return originalString;         }         String result = new String(originalString);         while (result.lastIndexOf(character) == result.length() - 1) {             result = removeLastCharacter(result);             if (result.length() == 0) {                 return "";             }         }         return result;     }     /**      * <p>Simply removes the last character</p>      * @param originalString      * @return a new String without the      * @throws IllegalArgumentException if the string is null      */     public static String removeFirstCharacter(String originalString) {         if (originalString == null) {             throw new IllegalArgumentException("string is null");         }         if (originalString.length() <= 1) {             return "";         }         return originalString.substring(1);     }     /**      * <p>Simply removes the last character</p>      * @param originalString      * @return a new String without the      * @throws IllegalArgumentException if the string is null      */     public static String removeLastCharacter(String originalString) {         if (originalString == null) {             throw new IllegalArgumentException("string is null");         }         if (originalString.length() <= 1) {             return "";         }         return originalString.substring(0, originalString.length() - 1);     }     /**      * <p>This is a simpler alternative to original String.replaceAll function that uses complex Regexp.      * Here, you modify a String by changing the <strong>characters sequence</strong> sequenceToReplace by the replacement string.</p>      *      * <p>      * Exemple :<br/>      *  &nbsp;<code>String original = "//cooluri//living.js///";</code><br/>      * Then <br/>      *  &nbsp;<code>StringUtils.replaceAll(original,"//", "-");</code><br/>      * will return :<br/>      * -cooluri-living.js-/      * </p>      * <p>Note that the '///' is always seen as ('//'+'/') and <strong>never</strong> as ('/'+'//'). This function is <strong>sequential</strong>, and will not always work like regular expressions.</p>           * @param originalString The original string      * @param sequenceToReplace The characters sequence to replace      * @param replacement      * @return      * @throws IllegalArgumentExceptionif a param is null      */     public static String replaceSequence(String originalString, String sequenceToReplace, String replacement) {         if (originalString == null) {             throw new IllegalArgumentException("originalString is null");         }         if (sequenceToReplace == null) {             throw new IllegalArgumentException("charsToReplace is null");         }         if (replacement == null) {             throw new IllegalArgumentException("replacement is null");         }         if (sequenceToReplace.equals(replacement)){             return originalString;         }                  String newString = new String(originalString);         if (originalString == null || originalString.length() == 0) {             return originalString;         }         if (sequenceToReplace == null || sequenceToReplace.length() == 0) {             return originalString;         }         int indexPiece = originalString.indexOf(sequenceToReplace);         while (indexPiece != -1) {             newString = newString.substring(0, indexPiece) + replacement + newString.substring(indexPiece + sequenceToReplace.length());             indexPiece = newString.indexOf(sequenceToReplace);         }         return newString;     }     /**      * Replace any character defined in anyCharacter by a replacement sequence      * Ex :      * <pre>      * replaceAny("john jack jim", "ji", "t") => "tohn tack ttm"      * </pre>      * @param originalString      * @param anyCharacter      * @param replacement      * @return      */     public static String replaceAny(String originalString, String anyCharacter, String replacement){         String worker = originalString;         for (Character c : anyCharacter.toCharArray()){             String pattern = ""+c;             worker = worker.replaceAll(pattern, replacement);         }         return worker;     }     /**      * <p>Keeps the 'number' first characters, and might be useful to keep your user's privacy :<br/>      * &nbsp;<code>truncate("Hernandez", 3)</code><br/>      * will produce: "Her"      *</p>      * <p>      * If number is bigger than the size of the String, the whole string is kept : <br/>      * &nbsp;<code>truncate("Hernandez", 24)</code><br/>      * will produce: "Hernandez"      *</p>      * <p>If number==0, the function returns an empty string.</p>      * @param originalString      * @param number      * @return a new smaller String.      * @throws IllegalArgumentException if number<0 or original is null      */     public static String truncate(String original, int number) {         if (number < 0) {             throw new IllegalArgumentException("number :" + number + " is <0");         }         if (original == null) {             throw new IllegalArgumentException("original string is null");         }         String newLastName = original.length() >= number ? original.substring(0, number) : original;         return newLastName;     }     /**      * If stringToTes contains any character in 'characatersToTest', the function returns true, false if not      * @param stringToTest      * @param charatersToTest      * @return true if stringToTes contains any character in 'characatersToTest'      * @throws IllegalArgumentException if charactersToTest is null or empty      */     public static boolean containsCharacter(String stringToTest, String charatersToTest) {         if (charatersToTest == null) {             throw new IllegalArgumentException("characters is null");         }         if (charatersToTest.length() == 0) {             throw new IllegalArgumentException("No character to Test");         }         for (int i = 0; i < charatersToTest.length(); i++) {             char c = charatersToTest.charAt(i);             if (stringToTest.contains(String.valueOf(c))) {                 return true;             }         }         return false;     }        /**      * Returns the concatenation of the absolute and relative paths, adding a "/" character between them if needed      * Calling addPath(uri, "/") ensures that the path will finish with only one "/" (as long as uri doesn't finishes with more than one "/")      * @param absolute      * @param relative      * @return      */     public static String addPath(String absolute, String relative){         return removeTrailingCharacters(absolute, '/')+"/"+removeStartingCharacters(relative, '/');     }     /**      * Add the protocol to the String      * @param protocol      * @param uri      * @return a new Stirng with the protocol      */     public static String addProtocol(String protocol, String uri){         String worker=removeTrailingCharacters(protocol, '/');         worker=removeTrailingCharacters(worker, ':');         return worker+"://"+removeStartingCharacters(uri, '/');     }     /**      * Needed for Gwt Compatibility : GWT does not yet provide a getSimpleClassName      * @param o      * @return      */     public static String getSimpleClassName(Object o) {         String className = o.getClass().getName();         return className.substring(                 className.lastIndexOf(".") + 1, className.length());     }     /**      * Return a String that starts with an Uppercase character, and ends with LowerCase characters      * strictCapitalize("johnDoe") returns Johndoe      * @param string string to capitalize      * @return a String that starts with an Uppercase character, and ends with LowerCase characters      * @see #simpleCapitalize(java.lang.String)       */     public static String strictCapitalize(String str) {         if (str == null){             throw new IllegalArgumentException("String is null");         }         if (str.length() == 0) {             return str;         }         String worker = str.toLowerCase();         return worker.substring(0, 1).toUpperCase() + worker.substring(1);     }     /**      * Capitalize the first letter, and doesn't touch any other      * simpleCapitalize("johnDoe") returns JohnDoe      * @param string string to capitalize      * @return the same string with capitalized first letter      * @see #strictCapitalize(java.lang.String)       */     public static String simpleCapitalize(String str){         if (str == null){             throw new IllegalArgumentException("String is null");         }         if (str.length() == 0) {             return str;         }         String work = new String(str);         return work.substring(0, 1).toUpperCase() + work.substring(1);     }     /**      * TODO 1 : work on this ; Use StringTokenizer      * <p>Splits the provided text into an array ,* separators specified.</p>      *      * <p>The separator is not included in the returned String array.      * Adjacent separators are treated as one separator.</p>      *      * <pre>           * StringUtils.split("ab de fg", " ")   = ["ab", "de", "fg"]      * StringUtils.split("ab   de fg", " ") = ["ab", "cd", "ef"]      * StringUtils.split("ab:cd:ef", ":")    = ["ab", "cd", "ef"]      * </pre>      *      * @param string  the String to parse, may be null      * @param separatorChars  the characters used as the delimiters      * @return an array of parsed Strings      * @throws IllegalArgumentException if string or separatorChars is null, or if separatorChars is empty      */     public static String[] split(String string, String separatorChars){         if (string == null){             throw new IllegalArgumentException("string argument is null");         }         if (separatorChars == null || separatorChars.length() == 0){             throw new IllegalArgumentException("separators is null or empty");         }         List<String> resultList = new ArrayList<String>();         String worker =new String(string);         String firstSeparator = separatorChars.substring(0, 1);         assert firstSeparator.length() == 1;         char[] charArray = separatorChars.toCharArray();         //We replace multiple instance of other separator by only one firstSeparator         for (int i = 1 ; i < charArray.length ; i++){             String pattern = "("+charArray[i]+")+";             worker = worker.replaceAll(pattern, firstSeparator);         }                  //One more pass for the first separator         String pattern = "("+firstSeparator+")+";         worker = worker.replaceAll(pattern, firstSeparator);         System.out.println("separator : "+firstSeparator+" ; worker : "+worker);         Collections.addAll(resultList, worker.split(firstSeparator) );         return (String[]) resultList.toArray(new String[resultList.size()]);            }     /**      * @todo3 : to be tested      * Join elements      * @param strings      * @param join      * @return      */     public static String join (Object [] strings, String joint){         if (strings == null){             throw new IllegalArgumentException("strings array is null");         }         if (joint == null){             throw new IllegalArgumentException("No joint ; use empty String instead of null");         }         StringBuilder sb = new StringBuilder();         for (int i = 0 ; i < strings.length ; i++){             sb.append(strings[i].toString());             //if not last             if (i < strings.length - 1 && joint.length()>0){                 sb.append(joint);             }         }         return sb.toString();     }     public static String defaultJoints = " _-";          /**      * Transfom joints in capital characters      * Chateau De Versailles => ChateauDeVersaille      * white_house => whiteHouse  (House is now capitalized)      * groovyStyle_grails => groovyStyleGrails (inside capitals are untouched)      * One difference with Java style is that the first letter might stay a capital      *      * If specifiedJoints == null, the method uses default ones : " _-", thought this      * can be changed with the {@link StringUtils#defaultJoints}      *      * @param string      * @return      */     public static String normalize(String string, String specifiedJoints){         if (specifiedJoints == null){             specifiedJoints = defaultJoints;         }         String worker = replaceAny(string, specifiedJoints, " ");         String [] array = split(worker, " ");         for (int i = 0 ; i < array.length ; i++){             String s = array[i];             if (i>0){                 array[i] = simpleCapitalize(s);             }                      }         return join(array, "");     } }