Java 检测字符串是否包含多个单词的更好方法
我正在尝试创建一个程序,该程序可以尽可能快地检测字符串中是否有多个单词,如果是,则执行一个行为。最好是,我希望它也能检测出这些单词的顺序,但前提是能够快速完成。到目前为止,我所做的就是:Java 检测字符串是否包含多个单词的更好方法,java,string,substring,contains,Java,String,Substring,Contains,我正在尝试创建一个程序,该程序可以尽可能快地检测字符串中是否有多个单词,如果是,则执行一个行为。最好是,我希望它也能检测出这些单词的顺序,但前提是能够快速完成。到目前为止,我所做的就是: if (input.contains("adsf") && input.contains("qwer")) { execute(); } 正如你所看到的,对多个单词这样做会让人厌烦。这是检测多个子字符串的唯一方法还是有更好的方
if (input.contains("adsf") && input.contains("qwer")) {
execute();
}
正如你所看到的,对多个单词这样做会让人厌烦。这是检测多个子字符串的唯一方法还是有更好的方法?有没有办法检测秩序
编辑们注意:尽管获得了大量的投票和认可,但这与问题中的代码功能不同<在第一次匹配时调用code>execute,就像逻辑OR
您可以使用数组:
String[] matches = new String[] {"adsf", "qwer"};
bool found = false;
for (String s : matches)
{
if (input.contains(s))
{
execute();
break;
}
}
这与您发布的一样高效,但更易于维护。寻找一个更有效的解决方案听起来像是一个微优化,在被证明是代码的瓶颈之前,应该忽略它。在任何情况下,如果设置了一个巨大的字符串集,这个解决方案可能是一个trie。我会用以下文字创建一个正则表达式:
Pattern pattern = Pattern.compile("(?=.*adsf)(?=.*qwer)");
if (pattern.matcher(input).find()) {
execute();
}
有关更多详细信息,请参见以下答案:如果要查找大量子字符串,则正则表达式可能不会有多大帮助,因此最好将这些子字符串放在列表中,然后对它们进行迭代,并对每个子字符串调用
input.indexOf(substring)
。这将返回找到子字符串的位置的int
索引。如果将每个结果(除了-1,这意味着找不到子字符串)抛出到树映射中(其中index
是键,子字符串是值),则可以通过调用映射上的keys()
按顺序检索它们
Map<Integer, String> substringIndices = new TreeMap<Integer, String>();
List<String> substrings = new ArrayList<String>();
substrings.add("asdf");
// etc.
for (String substring : substrings) {
int index = input.indexOf(substring);
if (index != -1) {
substringIndices.put(index, substring);
}
}
for (Integer index : substringIndices.keys()) {
System.out.println(substringIndices.get(index));
}
Map substringindex=newtreemap();
List substring=new ArrayList();
子字符串。添加(“asdf”);
//等等。
for(字符串子字符串:子字符串){
int index=input.indexOf(子字符串);
如果(索引!=-1){
substringindex.put(index,substring);
}
}
for(整数索引:substringindex.keys()){
System.out.println(substringindex.get(index));
}
使用树结构来保存每个码点的子字符串。这样就不需要
请注意,只有当针组几乎恒定时,这才有效。但是,如果单独添加或删除子字符串并不是效率低下的,但是每次不同的初始化将大量字符串排列到树结构中肯定会减慢速度
StringSearcher
:
在Java8中,您可以
public static boolean containsWords(String input, String[] words) {
return Arrays.stream(words).allMatch(input::contains);
}
示例用法:
String input = "hello, world!";
String[] words = {"hello", "world"};
if (containsWords(input, words)) System.out.println("Match");
这是一个经典的面试和CS问题
罗宾·卡普算法通常是人们在采访中首先谈论的。基本思想是在遍历字符串时,将当前字符添加到哈希中。如果哈希值与某个匹配字符串的哈希值匹配,则您知道可能存在匹配项。这样可以避免来回扫描匹配字符串。
<> P>面试问题的其他典型主题是考虑TIE结构以加快查找速度。如果有一大组匹配字符串,则必须始终检查一大组匹配字符串。trie结构更有效地执行该检查。
其他算法包括:
-阿霍-科拉西克
-Commentz Walter我认为更好的方法是这样的,我们可以将多个值作为一个字符串添加,并通过函数的索引验证索引
String s = "123";
System.out.println(s.indexOf("1")); // 0
System.out.println(s.indexOf("2")); // 1
System.out.println(s.indexOf("5")); // -1
嗯,我相信这对我的小项目来说应该很有效。谢谢你这么快的回复!这实际上与所讨论的代码的工作原理相同吗?这个应该更像or运算符。对于要匹配的大型单词集,一个选项是aho corasick算法,请尝试此库->快速性能改进是用for-i循环替换for-each。对于Java中的每个对象,都创建一个迭代器对象。对象创建是昂贵的。如果您正在优化在200ms内执行的代码,那么这种优化是不值得的。但是,如果您要优化更关键的性能,避免对象创建会产生巨大的影响。@ThomasFischer:如果代码是时间关键的,那么问题就在于算法本身,一种更快的方法(如针对多个字符串优化的Bayer Moore)这将是一个合适的解决方案。这只处理匹配的第一个单词,并根据我的判断返回true,如果所有单词都在输入字符串中,则不匹配。我喜欢在此处使用正则表达式,但在浏览大量文本时,这对我来说非常缓慢。我发现@Jack的答案要快得多(在我的用例中)。同意,regexp本身非常昂贵,如果需要最高的速度,就不应该使用它们。如果目标是可维护性(从“对多个单词执行此操作将变得很烦人”的问题来看),那么此解决方案无法解决这一问题。每个单词额外使用6个字符。
String input = "hello, world!";
String[] words = {"hello", "world"};
if (containsWords(input, words)) System.out.println("Match");
String s = "123";
System.out.println(s.indexOf("1")); // 0
System.out.println(s.indexOf("2")); // 1
System.out.println(s.indexOf("5")); // -1