173 lines
6.4 KiB
Java
173 lines
6.4 KiB
Java
package me.teridax.jcash.decode;
|
|
|
|
import org.junit.Test;
|
|
|
|
import java.text.NumberFormat;
|
|
import java.text.ParseException;
|
|
import java.util.Locale;
|
|
import java.util.Objects;
|
|
import java.util.regex.Pattern;
|
|
|
|
import static junit.framework.TestCase.assertEquals;
|
|
|
|
/**
|
|
* Utility class for converting various single line strings into a specific data type according
|
|
* to a format mostly dictated by a locale.
|
|
*/
|
|
public class StringDecoder {
|
|
|
|
/**
|
|
* Locale to use when converting strings
|
|
*/
|
|
private static final Locale LOCALE = Locale.GERMANY;
|
|
/**
|
|
* NumberFormat to use when converting strings
|
|
*/
|
|
public static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE);
|
|
|
|
/**
|
|
* Attempts to convert the given string into a double value representing a percentage.
|
|
* The percentage is stored in the range [0,1] and can linearly be mapped to [0, 100] by multiplying with 100.
|
|
* @param number the string to convert
|
|
* @return the double value
|
|
* @throws IllegalArgumentException when the format is invalid
|
|
* @throws NullPointerException when the argument is null
|
|
*/
|
|
public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException {
|
|
Objects.requireNonNull(number);
|
|
|
|
// trim the number and cut out optional percent symbols
|
|
var trimmed = number.trim().replace("%", "");
|
|
|
|
try {
|
|
return LOCAL_NUMBER_FORMAT.parse(trimmed).doubleValue();
|
|
} catch (ParseException ex) {
|
|
throw new IllegalArgumentException("Not a valid number: " + number, ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to convert the given string into a currency value.
|
|
* @param currency the string to convert
|
|
* @return the double value
|
|
* @throws IllegalArgumentException when the format is invalid
|
|
* @throws NullPointerException when the argument is null
|
|
*/
|
|
public static double decodeCurrency(String currency) throws IllegalArgumentException, NullPointerException {
|
|
Objects.requireNonNull(currency);
|
|
|
|
try {
|
|
return LOCAL_NUMBER_FORMAT.parse(currency.trim()).doubleValue();
|
|
} catch (ParseException ex) {
|
|
throw new IllegalArgumentException("Not a valid currency in german locale: " + currency, ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to convert the given string into universally unique number.
|
|
* This function does not check for duplicates. The number must be a positive integer.
|
|
* @param number the string to convert
|
|
* @return the integer serial number
|
|
* @throws IllegalArgumentException when the format is invalid
|
|
* @throws NullPointerException when the argument is null
|
|
*/
|
|
public static int decodeUniqueIdentificationNumber(String number) throws IllegalArgumentException, NullPointerException {
|
|
Objects.requireNonNull(number);
|
|
|
|
// check if the string is a valid unsigned number
|
|
try {
|
|
LOCAL_NUMBER_FORMAT.setParseIntegerOnly(true);
|
|
var serialNumber = LOCAL_NUMBER_FORMAT.parse(number.trim());
|
|
LOCAL_NUMBER_FORMAT.setParseIntegerOnly(false);
|
|
|
|
if (serialNumber.intValue() < 0)
|
|
throw new IllegalArgumentException("Not a valid unique identification number: " + number);
|
|
|
|
return serialNumber.intValue();
|
|
} catch (ParseException ex) {
|
|
throw new IllegalArgumentException("Not a valid serial number: " + number, ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to convert the given string into a name.
|
|
* This method performs validation and trimming.
|
|
* @param name the string to convert
|
|
* @return the qualified name
|
|
* @throws IllegalArgumentException when the format is invalid
|
|
* @throws NullPointerException when the argument is null
|
|
*/
|
|
public static String decodeName(String name) throws IllegalArgumentException, NullPointerException {
|
|
Objects.requireNonNull(name);
|
|
|
|
var trimmed = name.trim();
|
|
|
|
var pattern = Pattern.compile("[\\w-\\s]+", Pattern.CASE_INSENSITIVE);
|
|
var matcher = pattern.matcher(trimmed);
|
|
if (matcher.find()) {
|
|
return matcher.group();
|
|
} else {
|
|
throw new IllegalArgumentException("not a void name");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to convert the given string into a street and an optional house address.
|
|
* @param street the string to convert
|
|
* @return the address name
|
|
* @throws IllegalArgumentException when the format is invalid
|
|
* @throws NullPointerException when the argument is null
|
|
*/
|
|
public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException {
|
|
Objects.requireNonNull(street);
|
|
|
|
var pattern = Pattern.compile("\\S+(\\s+\\d+(/\\d+)?)?", Pattern.CASE_INSENSITIVE);
|
|
var matcher = pattern.matcher(street);
|
|
if (matcher.find()) {
|
|
return matcher.group();
|
|
} else {
|
|
throw new IllegalArgumentException("not a void address");
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testDecodeSuccessfulFunctions() {
|
|
decodeUniqueIdentificationNumber("95786978625347895");
|
|
decodeUniqueIdentificationNumber(" 927856347 ");
|
|
decodeUniqueIdentificationNumber("0");
|
|
|
|
decodeName("Adolf");
|
|
decodeName("Günther");
|
|
decodeName("Saßkia");
|
|
|
|
decodeStreet("Bahnhofstraße 40/1");
|
|
decodeStreet("Gülleweg 9");
|
|
decodeStreet("Echsengaße 67 / 4");
|
|
|
|
assertEquals(decodePercent("1,4%"), 1.4d);
|
|
assertEquals(decodePercent("99"), 99.0d);
|
|
assertEquals(decodePercent("1,003 %"), 1.003d);
|
|
|
|
assertEquals(decodeCurrency("1,3€"), 1.3d);
|
|
assertEquals(decodeCurrency("145,34"), 145,34d);
|
|
assertEquals(decodeCurrency("0,45 €"), 0.45d);
|
|
}
|
|
|
|
@Test(expected = IllegalArgumentException.class)
|
|
public void testDecodeInvalidFunctions() {
|
|
decodeUniqueIdentificationNumber("q0948tvb6q047t 740 t74z0tz 784");
|
|
decodeUniqueIdentificationNumber("-39867.8475");
|
|
decodeUniqueIdentificationNumber("-398678475");
|
|
decodeUniqueIdentificationNumber(" ß9qu908t76q34798t6q734vb9843");
|
|
|
|
decodeName("John Doe");
|
|
decodeName("3490qt67v 0b34");
|
|
decodeName("Alexander9");
|
|
decodeName("-ga76re78g6$§");
|
|
|
|
decodeStreet("Bahnhofstraße -40/1");
|
|
decodeStreet("Gülleweg 9//567");
|
|
decodeStreet("23Echsengaße 67 / 4 Hofwetg 9");
|
|
}
|
|
}
|