Po odpovědi od Kazimíra jsem se rozhodl vzít to trochu dále a provedeny některé kód, aby skutečně analyzovat celá čísla stejně, jsou uvedeny níže. To zahrnuje minus a plus symboly, i když ty jsou oficiálně není součástí literálu, jak je popsáno v JLS; jsou unární operátory.
package nl.owlstead.ifprops;
import java.math.BigInteger;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class JavaIntegerParser {
private static final Pattern BINARY = Pattern.compile("(0b)([01](?:_*[01])*)(L?)", Pattern.CASE_INSENSITIVE);
private static final Pattern OCTAL = Pattern.compile("(0)([0-7](?:_*[0-7])*)(L?)", Pattern.CASE_INSENSITIVE);
private static final Pattern DECIMAL = Pattern.compile("()(0|(?:[1-9](?:_*[0-9])*))(L?)", Pattern.CASE_INSENSITIVE);
private static final Pattern HEXADECIMAL = Pattern.compile("(0x)([0-9a-f](?:_*[0-9a-f])*)(L?)", Pattern.CASE_INSENSITIVE);
// NOTE: OCTAL should be before DECIMAL if this is used to find the pattern
private static final Pattern SIGNED_INTEGER_LITERAL = Pattern.compile(
"(?:([+-])\\s*)?(" +
BINARY + "|" + OCTAL + "|" + DECIMAL + "|" + HEXADECIMAL +
")", Pattern.CASE_INSENSITIVE);
public static int parseJavaInteger(String javaInteger) throws NumberFormatException {
BigInteger value = parseIntegerAsBigInt(javaInteger);
try {
return value.intValueExact();
} catch (@SuppressWarnings("unused") ArithmeticException e) {
throw new NumberFormatException("Number is not between Integer.MIN_VALUE and Integer.MAX_VALUE");
}
}
public static long parseJavaLong(String javaLong) throws NumberFormatException {
BigInteger value = parseIntegerAsBigInt(javaLong);
try {
return value.longValueExact();
} catch (@SuppressWarnings("unused") ArithmeticException e) {
throw new NumberFormatException("Number is not between Integer.MIN_VALUE and Integer.MAX_VALUE");
}
}
private static BigInteger parseIntegerAsBigInt(String javaLiteral) {
Matcher intMatcher = SIGNED_INTEGER_LITERAL.matcher(javaLiteral);
if (!intMatcher.matches()) {
throw new NumberFormatException(javaLiteral + " is not recognized as a Java integer literal");
}
String signGroup = intMatcher.group(1);
String prefixAndValueGroup = intMatcher.group(2);
String radixGroup = "";
String valueGroup = "";
// String longGroup = "";
List<Pattern> patterns = List.of(BINARY, OCTAL, DECIMAL, HEXADECIMAL);
for (Pattern pattern : patterns) {
Matcher specificMatcher = pattern.matcher(prefixAndValueGroup);
if (specificMatcher.matches()) {
radixGroup = specificMatcher.group(1);
valueGroup = specificMatcher.group(2);
// longGroup = specificMatcher.group(3);
break;
}
}
if (valueGroup == null) {
throw new RuntimeException("Number both matches but doesn't contain a value (parser error)");
}
BigInteger sign = signGroup != null && signGroup.matches("-") ? BigInteger.ONE.negate() : BigInteger.ONE;
int radix;
switch (radixGroup.toLowerCase()) {
case "0b":
radix = 2;
break;
case "0":
radix = 8;
break;
case "":
radix = 10;
break;
case "0x":
radix = 16;
break;
default:
throw new RuntimeException();
}
BigInteger value = new BigInteger(valueGroup.replaceAll("_", ""), radix).multiply(sign);
return value;
}
}
Také jsem se snažil použít kód najít více celých čísel z řetězce, ale to nedopadlo dobře. Problém je, že některé neplatné znaky, jako například 0__0
přijali jako dva literály s hodnotou nula; není přesně to, co chcete. Takže prosím, používat regulární výrazy pouze ke zjištění, zda řetězec je vlastně číslo a oddělit celá čísla např. pomocí String.split(SEPARATOR_REGEX)
.
Legrační dost, moje Eclipse IDE to přijmout 0__0
jako doslovný, i když to oficiálně není kompatibilní s JLS. Ne v poho, ale divné none-the-méně.
?
by měla být*
?