我在应用程序中加载了一个字符串,它可以从数字变成字母等等。我有一个简单的if语句,看看它是否包含字母或数字,但是,有些东西不太正确。下面是一个片段。
String text = "abc";
String number;
if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
number = text;
}
虽然文本变量包含字母,但条件返回为true。和&&应该eval作为两个条件都必须为真,以便处理number =文本;
==============================
解决方案:
我能够通过使用以下代码来解决这个问题,该代码由对这个问题的评论提供。所有其他帖子也是有效的!
我使用的有效方法来自第一条评论。尽管提供的所有示例代码似乎也是有效的!
String text = "abc";
String number;
if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
number = text;
}
在性能方面,parseInt和其他解决方案要差得多,因为至少需要异常处理。
我已经运行了jmh测试,并发现使用charAt遍历字符串并将字符与边界字符进行比较是测试字符串是否只包含数字的最快方法。
JMH测试
测试比较Character的性能。isDigit vs Pattern.matcher()。比赛vs长。parseLong vs检查char值。
对于非ascii字符串和包含+/-号的字符串,这些方法可以产生不同的结果。
测试在吞吐量模式下运行(越大越好),包括5个预热迭代和5个测试迭代。
结果
注意,在第一次测试加载时,parseLong几乎比isDigit慢100倍。
## Test load with 25% valid strings (75% strings contain non-digit symbols)
Benchmark Mode Cnt Score Error Units
testIsDigit thrpt 5 9.275 ± 2.348 ops/s
testPattern thrpt 5 2.135 ± 0.697 ops/s
testParseLong thrpt 5 0.166 ± 0.021 ops/s
## Test load with 50% valid strings (50% strings contain non-digit symbols)
Benchmark Mode Cnt Score Error Units
testCharBetween thrpt 5 16.773 ± 0.401 ops/s
testCharAtIsDigit thrpt 5 8.917 ± 0.767 ops/s
testCharArrayIsDigit thrpt 5 6.553 ± 0.425 ops/s
testPattern thrpt 5 1.287 ± 0.057 ops/s
testIntStreamCodes thrpt 5 0.966 ± 0.051 ops/s
testParseLong thrpt 5 0.174 ± 0.013 ops/s
testParseInt thrpt 5 0.078 ± 0.001 ops/s
测试套件
@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
private static final long CYCLES = 1_000_000L;
private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
private static final Pattern PATTERN = Pattern.compile("\\d+");
@Benchmark
public void testPattern() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
b = PATTERN.matcher(s).matches();
}
}
}
@Benchmark
public void testParseLong() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
try {
Long.parseLong(s);
b = true;
} catch (NumberFormatException e) {
// no-op
}
}
}
}
@Benchmark
public void testCharArrayIsDigit() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (char c : s.toCharArray()) {
b = Character.isDigit(c);
if (!b) {
break;
}
}
}
}
}
@Benchmark
public void testCharAtIsDigit() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (int j = 0; j < s.length(); j++) {
b = Character.isDigit(s.charAt(j));
if (!b) {
break;
}
}
}
}
}
@Benchmark
public void testIntStreamCodes() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
b = s.chars().allMatch(c -> c > 47 && c < 58);
}
}
}
@Benchmark
public void testCharBetween() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (int j = 0; j < s.length(); j++) {
char charr = s.charAt(j);
b = '0' <= charr && charr <= '9';
if (!b) {
break;
}
}
}
}
}
}
2018年2月23日更新
再添加两种情况——一种使用charAt而不是创建额外的数组,另一种使用IntStream的char代码
如果在循环测试用例中发现非数字,则添加立即中断
对于循环测试用例,空字符串返回false
2018年2月23日更新
再添加一个不使用流比较char值的测试用例(最快的!)
你可以使用正则表达式。匹配
if(text.matches("\\d*")&& text.length() > 2){
System.out.println("number");
}
或者你可以使用像Integer.parseInt(String)或更好的Long.parseLong(String)这样的onversions来获得更大的数字
比如:
private boolean onlyContainsNumbers(String text) {
try {
Long.parseLong(text);
return true;
} catch (NumberFormatException ex) {
return false;
}
}
然后用:
if (onlyContainsNumbers(text) && text.length() > 2) {
// do Stuff
}