Reputation: 421
I have a String like "09a" and I need a method to confirm if the text is hexadecimal. The code I've posted does something similar, it verifies that a string is a decimal number. I want to do the same, but for hexadecimal.
private static boolean isNumeric(String cadena) {
try {
Long.parseLong(cadena);
return true;
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(null,"Uno de los números, excede su capacidad.");
return false;
}
}
Upvotes: 42
Views: 97988
Reputation:
Try this.
static boolean isHexadecimal(String s) {
return s.chars()
.skip(s.startsWith("-") ? 1 : 0)
.allMatch(c -> "0123456789ABCDEFabcdef".indexOf(c) >= 0);
}
public static void main(String[] args) {
System.out.println(isHexadecimal("-0e34a29Fb"));
System.out.println(isHexadecimal("-ff-"));
System.out.println(isHexadecimal("ef-"));
System.out.println(isHexadecimal("efg"));
}
output:
true
false
false
false
You can omit .skip(s.startsWith("-") ? 1 : 0)
if you do not allow the sign.
Upvotes: 1
Reputation: 1976
Here some code for different options and execution time results (JDK 11):
execution time isHex1: 3670 ms
execution time isHex2: 3294 ms
execution time isHex3: 3946 ms
execution time regex: 31288 ms
Test code:
public class HexPerformanceTest {
@Test
public void testPerformance() {
int count = 100000000;
char[] chars = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
String regexString = new String(chars);
Predicate<String> isHex1Test = testString -> {
boolean isHex = true;
for (char c: testString.toCharArray()) {
if (!isHex1(c)) {
isHex = false;
break;
}
}
return isHex;
};
Predicate<String> isHex2Test = testString -> {
boolean isHex = true;
for (char c: testString.toCharArray()) {
if (!isHex2(c)) {
isHex = false;
break;
}
}
return isHex;
};
Predicate<String> isHex3Test = testString -> {
boolean isHex = true;
for (char c: testString.toCharArray()) {
if (!isHex3(c)) {
isHex = false;
break;
}
}
return isHex;
};
Pattern pattern = Pattern.compile("^[0-9a-fA-F]+$");
Predicate<String> regexTest = testString -> {
Matcher matcher = pattern.matcher(regexString);
return matcher.matches();
};
System.out.println("execution time isHex1: " + milliseconds(regexString, isHex1Test, count) + " ms");
System.out.println("execution time isHex2: " + milliseconds(regexString, isHex2Test, count) + " ms");
System.out.println("execution time isHex3: " + milliseconds(regexString, isHex3Test, count) + " ms");
System.out.println("execution time regex: " + milliseconds(regexString, regexTest, count) + " ms");
}
private long milliseconds(String testString, Predicate<String> hexTest, int count) {
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
hexTest.test(testString);
}
return System.currentTimeMillis() - start;
}
private boolean isHex1(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private boolean isHex2(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return true;
default:
return false;
}
}
private boolean isHex3(char c) {
return (Character.digit(c, 16) != -1);
}
}
Upvotes: 13
Reputation: 136002
Horrible abuse of exceptions. Don't ever do this! (It's not me, it's Josh Bloch's Effective Java). Anyway, I suggest
private static final Pattern HEXADECIMAL_PATTERN = Pattern.compile("\\p{XDigit}+");
private boolean isHexadecimal(String input) {
final Matcher matcher = HEXADECIMAL_PATTERN.matcher(input);
return matcher.matches();
}
Upvotes: 39
Reputation: 9
You can check any length text with below method practically.
public static boolean isHexadecimal(String text) {
Objects.requireNonNull(text);
if(text.length() < 1)
throw new IllegalArgumentException("Text cannot be empty.");
char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
for (char symbol : text.toCharArray()) {
boolean found = false;
for (char hexDigit : hexDigits) {
if (symbol == hexDigit) {
found = true;
break;
}
}
if(!found)
return false;
}
return true;
}
Upvotes: 0
Reputation: 5597
Used this in my own code to check if string is a MAC address
boolean isHex = mac_addr.matches("^[0-9a-fA-F]+$");
My beef with the other answers provided in this thread is that if the String's length is large, it would throw an exception as well. Therefore, not very useful if you are testing if a MAC address consist of valid hexadecimals.
Don't be terrified of using regex!
Upvotes: 19
Reputation: 2262
No-library approach
public static boolean isHexadecimal(String value)
{
if (value.startsWith("-"))
{
value = value.substring(1);
}
value = value.toLowerCase();
if (value.length() <= 2 || !value.startsWith("0x"))
{
return false;
}
for (int i = 2; i < value.length(); i++)
{
char c = value.charAt(i);
if (!(c >= '0' && c <= '9' || c >= 'a' && c <= 'f'))
{
return false;
}
}
return true;
}
Upvotes: 2
Reputation: 22007
There's an overloaded Long.parseLong
that accepts a second parameter, specifying the radix:
Long.parseLong(cadena,16);
As an alternative, you could iterate over the characters in the string and call Character.digit(c,16)
on them (if any of them return -1
it's not a valid hexadecimal digit). This is especially useful if the string is too large to fit in a long
(as pointed out in the comments, that would cause an exception if the first method is used). Example:
private static boolean isNumeric(String cadena) {
if ( cadena.length() == 0 ||
(cadena.charAt(0) != '-' && Character.digit(cadena.charAt(0), 16) == -1))
return false;
if ( cadena.length() == 1 && cadena.charAt(0) == '-' )
return false;
for ( int i = 1 ; i < cadena.length() ; i++ )
if ( Character.digit(cadena.charAt(i), 16) == -1 )
return false;
return true;
}
BTW, I'd suggest separating the concerns of "testing for a valid number" and "displaying a message to the user", that's why I simply returned false
in the example above instead of notifying the user first.
Finally, you could simply use a regular expression:
cadena.matches("-?[0-9a-fA-F]+");
Upvotes: 36
Reputation: 3478
Long.parseLong has a second form that takes a radix as its second argument.
private static boolean isHexNumber (String cadena) {
try {
Long.parseLong(cadena, 16);
return true;
}
catch (NumberFormatException ex) {
// Error handling code...
return false;
}
}
Upvotes: 9