Java 模式匹配的有效方法
Efficicient way for Java pattern Matching
检查字符串是否匹配以下内容的最佳和最快方法是什么:"AB+SPACE+NUMBER+ANYTHING
例如:"AB 1234 DEFG"
我正在寻找最有效的方法,因为它将每分钟比较数千笔交易。
使用 string.matches
函数,该函数使用正则表达式进行字符串匹配。
string.matches("AB \d+.*");
^ ^ ^ ^
| | | |_ Anything
AB | Num
|
space
如果你想在数字后面加上 space,那么使用
"AB \d+ .+"
注意:我真的很不擅长编写高效的代码,除非我使用 scala,否则情况会有所不同,但现在我的 scala IDE 无法正常工作,所以你只能得到 java。
Java:(同样,可能效率不高)
public static boolean checkString(String original) {
int space1 = original.indexOf(" ");
String section1 = original.substring(0, space1);
String sections2Onwards = original.substring(space1+1, original.length());
int space2 = sections2Onwards.indexOf(" ");
String section2 = sections2Onwards.substring(0,space2);
String end = original.substring(space2+1, original.length());
//Now on to the good, fun part, making sure that it is in fact the right pattern
//This checks that every character in section1 is not a number
char[] section1Split = section1.toCharArray();
for (char c : section1Split) {
try {
new Integer(new String(new char[] {c}));
return false;
} catch(NumberFormatException n) {}
}
//Now check that section2 is a number
try {
new Integer(section2);
} catch(NumberFormatException n) {
return false;
}
//Making sure that there are no spaces in "anything"
//Ignore this if "anything" can include spaces
if(end.indexOf(" ") > -1) {
return false;
}
//Since all conditions are true, return true! This string is legit!
return true;
}
Avinash 的回答可能更好更快,但我(以及堆栈溢出的其他很多人)无法理解如何制作这些模式。
希望我有所帮助!
避免使用 yourString.matches(regex)
,因为每次使用 matches
时都需要重新编译正则表达式,这可能是一项昂贵的操作。
最好编译一次正则表达式并在需要时重用它,如
Pattern p = Pattern.compile(regex);//compile once
for (String data : dataCollection){
Matcher m = p.matcher(data);
//... if (m.foo(bar))//some condition
}
避免 matches
的另一个原因是它可以 return 为真,如果整个数据都匹配正则表达式,这意味着它需要遍历整个字符串,即使您可以立即做出决定在数据开头看到 AB 1234
部分后。
因此,与其检查字符串是否为 AB(space)digits(restOfData)
形式,这需要我们遍历 restOfData
部分,我们可以检查是否可以 find
AB(space)digits
部分 在字符串的开头。这样的正则表达式可能看起来像 ^AB\s\d+
^
- 表示字符串开头的锚点
AB
- 表示 AB 文本的文字
\s
- 空白字符之一
\d+
- 数字 ("\d"
) 可以出现一次或多次 (+
)
所以你的代码看起来像
private static final Pattern p = Pattern.compile("^AB\s\d+");
private static boolean validate(String data){
return p.matcher(data).find();
}
要提取最大吞吐量,您也许可以使用状态机击败预编译的正则表达式 Pattern
- 只要您可以对模式进行编码并且它不会改变。
enum Match {
Start {
@Override
Match match(char c) {
return A.match(c);
}
},
A {
@Override
Match match(char c) {
return c == 'A' ? B : Fail;
}
},
B {
@Override
Match match(char c) {
return c == 'B' ? Space : Fail;
}
},
Space {
@Override
Match match(char c) {
return c == ' ' ? Number : Fail;
}
},
Number {
@Override
Match match(char c) {
return Character.isDigit(c) ? Number : Anything;
}
},
Anything {
@Override
Match match(char c) {
return Anything;
}
},
Fail {
@Override
Match match(char c) {
return Fail;
}
};
abstract Match match(char c);
static boolean matches(String s) {
Match state = Start;
for (int i = 0; i < s.length() && state != Fail; i++) {
state = state.match(s.charAt(i));
}
return state != Fail;
}
}
public void test() {
List<String> tests = Arrays.asList("AB 123Hello", "ABC 123Hello", "AB Hello", "AB 0 Hello");
for (String s : tests) {
boolean match = Match.matches(s);
System.out.println(s + " - " + (match ? "Matches" : "Fails"));
}
}
实际上,可以动态构建这些状态机 - 这就是 Pattern.compile
所做的 - 但像这样发展自己的硬编码 有时 实现更快的吞吐量。
请务必在使用前根据标准 Java Pattern
测试您的状态机,因为很容易发生 Pattern
实际上更快一点的情况。
请注意,此处编码的数字可以为零。如果这是可以接受的,那么您可以完全跳过该状态,直接从 Space
转到 Anything
。如果不是,则添加 FirstDigit
状态以确保至少存在一位数字。您甚至可以在 FirstDigit
.
之后直接转到 Anything
检查字符串是否匹配以下内容的最佳和最快方法是什么:"AB+SPACE+NUMBER+ANYTHING
例如:"AB 1234 DEFG"
我正在寻找最有效的方法,因为它将每分钟比较数千笔交易。
使用 string.matches
函数,该函数使用正则表达式进行字符串匹配。
string.matches("AB \d+.*");
^ ^ ^ ^
| | | |_ Anything
AB | Num
|
space
如果你想在数字后面加上 space,那么使用
"AB \d+ .+"
注意:我真的很不擅长编写高效的代码,除非我使用 scala,否则情况会有所不同,但现在我的 scala IDE 无法正常工作,所以你只能得到 java。
Java:(同样,可能效率不高)
public static boolean checkString(String original) {
int space1 = original.indexOf(" ");
String section1 = original.substring(0, space1);
String sections2Onwards = original.substring(space1+1, original.length());
int space2 = sections2Onwards.indexOf(" ");
String section2 = sections2Onwards.substring(0,space2);
String end = original.substring(space2+1, original.length());
//Now on to the good, fun part, making sure that it is in fact the right pattern
//This checks that every character in section1 is not a number
char[] section1Split = section1.toCharArray();
for (char c : section1Split) {
try {
new Integer(new String(new char[] {c}));
return false;
} catch(NumberFormatException n) {}
}
//Now check that section2 is a number
try {
new Integer(section2);
} catch(NumberFormatException n) {
return false;
}
//Making sure that there are no spaces in "anything"
//Ignore this if "anything" can include spaces
if(end.indexOf(" ") > -1) {
return false;
}
//Since all conditions are true, return true! This string is legit!
return true;
}
Avinash 的回答可能更好更快,但我(以及堆栈溢出的其他很多人)无法理解如何制作这些模式。
希望我有所帮助!
避免使用 yourString.matches(regex)
,因为每次使用 matches
时都需要重新编译正则表达式,这可能是一项昂贵的操作。
最好编译一次正则表达式并在需要时重用它,如
Pattern p = Pattern.compile(regex);//compile once
for (String data : dataCollection){
Matcher m = p.matcher(data);
//... if (m.foo(bar))//some condition
}
避免 matches
的另一个原因是它可以 return 为真,如果整个数据都匹配正则表达式,这意味着它需要遍历整个字符串,即使您可以立即做出决定在数据开头看到 AB 1234
部分后。
因此,与其检查字符串是否为 AB(space)digits(restOfData)
形式,这需要我们遍历 restOfData
部分,我们可以检查是否可以 find
AB(space)digits
部分 在字符串的开头。这样的正则表达式可能看起来像 ^AB\s\d+
^
- 表示字符串开头的锚点AB
- 表示 AB 文本的文字\s
- 空白字符之一\d+
- 数字 ("\d"
) 可以出现一次或多次 (+
)
所以你的代码看起来像
private static final Pattern p = Pattern.compile("^AB\s\d+");
private static boolean validate(String data){
return p.matcher(data).find();
}
要提取最大吞吐量,您也许可以使用状态机击败预编译的正则表达式 Pattern
- 只要您可以对模式进行编码并且它不会改变。
enum Match {
Start {
@Override
Match match(char c) {
return A.match(c);
}
},
A {
@Override
Match match(char c) {
return c == 'A' ? B : Fail;
}
},
B {
@Override
Match match(char c) {
return c == 'B' ? Space : Fail;
}
},
Space {
@Override
Match match(char c) {
return c == ' ' ? Number : Fail;
}
},
Number {
@Override
Match match(char c) {
return Character.isDigit(c) ? Number : Anything;
}
},
Anything {
@Override
Match match(char c) {
return Anything;
}
},
Fail {
@Override
Match match(char c) {
return Fail;
}
};
abstract Match match(char c);
static boolean matches(String s) {
Match state = Start;
for (int i = 0; i < s.length() && state != Fail; i++) {
state = state.match(s.charAt(i));
}
return state != Fail;
}
}
public void test() {
List<String> tests = Arrays.asList("AB 123Hello", "ABC 123Hello", "AB Hello", "AB 0 Hello");
for (String s : tests) {
boolean match = Match.matches(s);
System.out.println(s + " - " + (match ? "Matches" : "Fails"));
}
}
实际上,可以动态构建这些状态机 - 这就是 Pattern.compile
所做的 - 但像这样发展自己的硬编码 有时 实现更快的吞吐量。
请务必在使用前根据标准 Java Pattern
测试您的状态机,因为很容易发生 Pattern
实际上更快一点的情况。
请注意,此处编码的数字可以为零。如果这是可以接受的,那么您可以完全跳过该状态,直接从 Space
转到 Anything
。如果不是,则添加 FirstDigit
状态以确保至少存在一位数字。您甚至可以在 FirstDigit
.
Anything