【问题标题】:Check if String contains multiple values stored in Array of strings检查字符串是否包含存储在字符串数组中的多个值
【发布时间】:2018-01-03 16:12:56
【问题描述】:

我正在尝试编写一个程序来检查一个字符串是否包含多个必须以特定顺序出现的单词,这些单词存储在字符串数组中

到目前为止我已经达到的目标

boolean Check = false;
Scanner S = new Scanner(System.in);            

System.out.println("What is your question?");
String input=S.nextLine();

String[] Words = {"pay","car"};

for (int i = 0; i <= Words.length -1  ; i++) {

    if (input.matches(".*\\b"+Words[i]+"\\b.*") && input.matches(".*\\b"+Words[1]+"\\b.*")) {
         Check = true;
    }
}
if (Check){
    System.out.println("30k Dollar");
} else{
    System.out.println("Wrong info! ");
}

基本上,我的代码所做的是例如当用户输入时 “我应该为这辆车付多少钱?”他会得到“30k Dollar”的答案

因为字符串“pay”和“car”都在我的字符串数组中。

案例2:如果用户输入“bla bla car bla bla pay”

他会得到同样的答案。

如何防止程序对 2 个不同的问题给出相同的答案?

在我的代码中我也使用了 Words[i] 和 Words[1],但是当我得到更大的单词列表时,这不起作用,我尝试使用嵌套循环,但它不起作用。

【问题讨论】:

  • 你为什么要阻止两个问题的相同答案,我认为它们应该是相同的,这两个问题都以正确的顺序从您的数组中包含多个单词,当您说多个单词时,您的意思是两个以上?
  • 对不起,我已经编辑了案例 2。即使字符串“汽车先出现,然后字符串“支付”,它也会显示相同的答案。多个词是指超过 2 个的数组单词我将如何比较

标签: java arrays regex string


【解决方案1】:

您不需要遍历输入的单词,只需生成完整的正则表达式:

String[] words = {"pay","car"};
String regex = ".*\\b" + String.join("\\b.*\\b", words) + "\\b.*";

String test1= "how much should i pay for the car?";
System.out.println(test1.matches(regex)); // True

String test2 = "bla bla car bla bla pay";
System.out.println(test2.matches(regex)); // False

【讨论】:

  • 这适用于单词数组中只有 {"pay", "car"} 但是当有超过 2 个单词时,用户必须输入所有单词才能获得回答?
  • 此解决方案与数组中的单词数无关,它将为匹配项生成正确的正则表达式。用户必须像以前一样输入句子,这不适合您的情况吗?
  • 我使用更紧凑的正则表达式生成编辑了我的解决方案
  • 不知何故我的 ide 接受了 String.join 并且非常感谢!
  • 您需要 Java 8 才能使用String.join
【解决方案2】:

我假设您总是寻找由空格分隔的单词,因此您可以使用 split 分隔单词

String inputWords[] = input.split(" ");

首先我们需要减少检查单词是否在我们的数组中的时间复杂度,这样我们就可以将数组填充到一个集合中,但是由于我们关心顺序,我们最好使用带有关键字的映射和索引的值数组中的那个单词

Map<String,Integer> map = new HashMap<>();
String[] words = {"pay","car"};
for(int i =0; i< words.length; i++)
        map.put(words[i], i);

所以现在你只需要遍历你的 inputWords 并检查所有单词是否都在那里并且你没有违反顺序,这个时间复杂度是 O(n)

int lastFoundIndex = -1;
int numFound =0;
for(int i=0; i < inputWords.length; i++) {

if(map.get(inputWords[i]) != null ) {
    if(map.get(inputWords[i]) < lastFoundIndex)
       break;
     lastFoundIndex = map.get(inputWords[i]);
      numFound ++;
}
}
if(numFound  >= words.length) // this condition means we are allowing more than occurence without violating the order

     system.out.println("30k Dollar");

else 
     System.out.println("Wrong info! ");

【讨论】:

  • if(map.get(inputWords[i])
  • @Bashar no , map value is Integer, "我们最好使用一个map,key是单词,value是数组中那个单词的索引"
【解决方案3】:

您可以将它们组合成一个正则表达式检查。您已经在之前或之后匹配任何字符(使用.*),所以基本上只需将您的正则表达式字符串连接到一个检查中。

if (input.matches(".*\\b" + Words[0] + "\\b.*\\b" + Words[1] + "\\b.*"))

编辑:响应“在我的代码中我也使用了 Words[i] 和 Words[1],但是当我得到更大的单词列表时这不起作用,我尝试使用嵌套循环但它不起作用。”

您可以迭代输入的单词来创建正则表达式字符串。 String regexPattern = ".*\\b" + String.Join("\\b.*\\b", Words) + "\\b.*";

EDIT2:这是我的答案和编辑与代码中的更多上下文相结合:

String[] Words = {"pay","car"};
String regexPattern = ".*\\b" + String.Join("\\b.*\\b", Words) + "\\b.*";

if (input.matches(regexPattern)) {
  System.out.println("30k Dollar");
} else {
  System.out.println("Wrong info!");
}

EDIT3:将 Words.Join() 替换为 String.Join() 因为我可以在没有编译器的情况下使用 Java,真正的 gud。

【讨论】:

  • 感谢您的回复,但这会导致与我们使用 Word[1](数组的索引 1)相同的问题,但后来当我在数组中获得更多单词时,我无法继续使用 Words[1 ] ,字[2]。正如我在主题中提到的,我尝试使用嵌套循环,但效果不佳
  • 旁注:由于您只是直接连接用户输入,如果用户使用任何保留的正则表达式字符,他们可能会出现奇怪的行为。您可能需要考虑在连接输入之前对其进行转义。显然,有一个 Pattern.quote 方法可以做到这一点:baeldung.com/java-regexp-escape-char
  • 更新了答案 w/sn-p 用于接受任意数量的输入单词。
  • 我不理解您的编辑?你能解释一下吗?
  • 您表示需要接受任意数量的单词作为输入,因此我的编辑只是将所有输入单词与\\b.*\\b 连接起来,以创建一个按顺序匹配整个单词集的正则表达式。这样您就不需要对任何单词输入的索引进行硬编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 2021-06-10
  • 2014-12-27
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 2015-09-08
相关资源
最近更新 更多