Java搜索字符串以查找子字符串UNLESS,前面是特定字符

时间:2016-10-17 00:49:31

标签: java string loops substring

我正在尝试编写一个Java程序,在用户输入的字符串中搜索特定的子字符串(xyz),并保持运行计数,除非该子字符串前面有句点。在课堂的这一点上,我们只使用了charAt和length,所以如果可能的话,我需要坚持下去。另外,我们根本没有使用正则表达式,所以它也在窗外。

我已经设法让程序按照需要运行,但有一个值得注意的例外:如果字符串以句点输入开始,则无法计算任何连续匹配。这是我到目前为止所得到的:

System.out.println("Give me a String:");
String s1 = kb.nextLine();

int index = 0;
int count = 0;

while(index <= s1.length() - 1 && s1.charAt(index) != '.')
{
        if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
        {
            count++;
        }
        index++;
}
System.out.println(count);

2 个答案:

答案 0 :(得分:1)

You can simply check the input string whether it starts with period. If so then  you can use the following piece of code to handle the validation.

if(s1.charAt(0)!='.')
{
while(index <= s1.length() - 1 && s1.charAt(index) != '.')
{
        if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
        {
            count++;
        }
        index++;
}
}
else
{
    index=1;
    while(index <= s1.length() - 1 && s1.charAt(index) != '.')
    {
            if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
            {
                count++;
            }
            index++;
    }
}
System.out.println(count);
}

答案 1 :(得分:0)

由于这似乎是一个家庭作业类型的问题,我将首先尝试引导您朝着正确的方向前进,并在以后提供解决方案。 我强烈建议您在查看我的解决方案(我发布后)之前,先自己解决问题,然后再继续阅读this page

首先,考虑您可以接收的输入类型。由于您没有指定任何限制,因此您可以获得以下内容:

  • &#34;&#34; (空字符串)
  • &#34; \ n&#34; (空白)
  • &#34; X&#34; (单个字符)
  • &#34; XX&#34; (两个字符串)
  • &#34; ABC&#34; (正确长度的字符串,但不包含您的子字符串)
  • &#34;名为.xyz&#34; (要忽略的子字符串)

我可以继续,但我相信你可以想出你可能收到的各种奇怪的东西组合。这些只是让您入门的几个示例(以及我已在评论中发布的那些)

接下来,考虑一下算法需要做什么。正如我在评论中所说,听起来你想要计算子串的出现次数&#34; xyz&#34;而忽略子串&#34; .xyz&#34;的出现。现在考虑一下你将如何寻找这些子串 - 你将在一个字符串中从左到右一次推进一个字符,寻找匹配这两种可能性之一的子字符串。当你找到其中一个时,你会忽略它或计算它。

希望这会有所帮助,正如我所说,我会在您有时间与代码搏斗之后发布解决方案。如果您确实解决了问题,请继续发布您的解决方案(可能会编辑您的问题以添加新代码或添加答案)最后我再次强烈建议您阅读 this page 如果你还没有。

编辑#1:

我想添加更多信息,那就是:你已经很清楚你需要做些什么来计算你的&#34; xyz&#34;此时的子串 - 尽管输入逻辑中存在小缺陷,例如&#34; xaz&#34;,这很容易修复。你需要关注的是如何忽略子串&#34; .xyz&#34;那么想想如何实现忽略逻辑,忽略它意味着什么呢?一旦你回答它应该开始为你而来。

编辑#2:

您将在下面找到解决问题的方法。再一次了解解决方案的工作原理并不仅仅是复制和粘贴它是非常重要的。如果你只是在不了解我的情况下复制我的代码,那么你就会因为你想要获得的教育而欺骗自己。我目前没有时间详细描述此代码的原因和方式,但我计划稍后再次编辑以添加这些详细信息。

import java.util.Scanner;

public class Main {
    private static Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        System.out.println("Give me a String:");
        String s1 = scan.nextLine();

        System.out.println(countSubstrings(s1));

    }

    public static int countSubstrings(String s1){
        int index = 0;
        int count = 0;

        while (index < s1.length()-2) {
            if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
                index++;
            }
            else if (index+2 < s1.length() && s1.charAt(index) == 'x' && s1.charAt(index + 1) == 'y'
                    && s1.charAt(index + 2) == 'z') {
                count++;
                index+=2;
            }
            index++;
        }
        return count;
    }

}

编辑#3:

以上是为什么上面的代码能够做到这一点的基本要点。首先,我们考虑这样一个事实,即我们在一个数组中以特定的顺序寻找3个项目(一个三元组),如果我们看到紧接在三元组的第一个项目之前的第四个项目(一个时期),那么我们需要忽略三重奏。

根据我之前的编辑,我们需要定义忽略的含义。在这种情况下,我们的意思是简单地不计算它,继续我们搜索有效的子串来计算。最简单的方法是在不增加index的情况下推进count

所以,问问自己以下几点:

  • 我的循环何时停止?由于我们正在寻找三元组,我们知道如果输入String的长度小于3或者我们尚未检查的字符串中剩下少于3个字符,我们就可以停止。例如,如果输入是&#34; xyzab&#34;当我们得到索引3时,我们知道没有可能的方法形成一个三元组,其中&#34; a&#34;是三联中的第一个角色,因此我们的计数完成了。

  • 有一段时间我不想在一段时间后跳过接下来的3个字符吗?毕竟目标是寻找三元组,所以我不想跳过3个字符而不仅仅是1个字符?是的,有时候你想要跳过3个字符,当你有&#34; .axyz&#34;因为一个有效的三元组可以在第二个字符超过该时期后立即开始。所以实际上你只想跳过1个字符。

这一点,以及索引在循环结束时总是递增1的事实(后面会有更多内容),这就是为什么while中的第一个条件只会使index提前1 :

if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
    index++;
}
  • 有没有时间我会看到一段时间而不想忽略(跳过)下一个角色?是的,当下一个字符是另一个字段时,因为它可能表示需要跳过另一个字符。考虑输入&#34; .. xyz&#34;如果您遇到第一个句点并跳过第二个句点会导致错误答案,因为您的算法可能会将接下来的三个字符视为有效三元组,但实际上由于第二个句点而无效。

这就是上述条件的后半部分存在的原因:

`&& s1.charAt(index+1) != '.'`
  • 现在问问自己如何识别有效的三元组。我相信你现在可以看到如何做到这一点 - 检查当前字符,下一个字符以及之后的字符,以获得所需的值。这个逻辑是while中第二个if条件的后一部分:

    s1.charAt(index) == 'x' && s1.charAt(index + 1) == 'y' && s1.charAt(index + 2) == 'z'

每当你在循环中使用索引+1或索引+2之类的计算时,它会递增索引直到达到边界,你必须考虑计算超出边界的可能性,因为你可以&# 39; t依赖循环为你检查这个,因为循环不会执行那个检查,直到循环的结束或开始(取决于它是哪种循环)

  • 考虑到上述情况,您必须问自己:当我使用这些索引+ 1,索引+ 2等类型的计算时,如何防止超出边界的情况?答案是为您的条件添加另一件:

index+2 < s1.length()

您可能想知道 - 为什么不添加两个检查,因为我们使用索引+ 1和索引+ 2?我们只需要检查一下,看看我们使用的最大索引是否会超过这种情况下的边界。如果指数+2超出界限,我们就不关心指数+ 1是否是因为它不重要,因为我们不可能有匹配的子串。

  • 接下来,在if内的第二个while内部,您会看到有代码将索引增加2:index+=2;这样做是为了提高效率,因为一旦我们确定了三元组我们知道没有办法形成另一个三元组,其中的角色已经是另一个三元组的一部分。因此,我们想跳过它们,就像第一个项目符号点一样,我们利用循环递增索引,所以我们只需要递增2并让循环在后面添加额外的1。

最后,我们到达循环内的逻辑结束。这部分你已经熟悉并且index++;只是增加了我们当前正在检查的字符串中的位置。请注意,这与第一个项目符号点一起使用。以&#34; .axyz&#34;的第一个项目符号为例。索引0中有一个句点,索引1中的字符不是另一个句点,因此第一个项目符号点的逻辑将索引增加1,使其为1.在循环结束时,索引再次递增,使其成为2,从而跳过在这段时间内 - 在下一个循环索引的开始处是2,它在循环开始时从不是1。

嗯,我希望这有助于解释它是如何工作的,并说明如何思考这些问题。基本原则是可视化当前元素的位置以及如何使用它来实现目标。同时考虑程序的不同元素具有哪些属性以及如何利用它们 - 例如,一旦识别出三元组,跳过这些字符是安全的,因为它们具有以下属性:只能使用一次。与任何程序一样,您总是希望尝试创建尽可能多的测试输入,以测试可能发生的所有奇怪的边界情况,以确保代码的正确性。我意识到你可能不熟悉JUnit但它是一个非常有用的工具,当你有一点空闲时间时,你可能会尝试研究使用它的基础知识,而且如果你使用{{3它集成了您可以使用的JUnit功能。