检查字符串是否包含某个单词,然后检查字符串是否以该单词开头,如果不是呢?

7

大家好,这里有一个棘手的问题,我想检查一个字符串是否包含单词 "Foo" ,如果包含,那么它是否以它开始?如果它确实以 Foo 开头,它应该是仅有的一个以大写字母开头的 Foo,所有其他的 Foo 应该是小写字母。

如果符合以上条件,它应该返回 true。

如果字符串包含了 Foo 但不以 Foo 开头,它应该立即返回 false,因为你不能在字符串中间有一个大写的 Foo。

如果字符串包含 foo 但不以 Foo 开头,所有 foo 的实例都应该是小写。如果符合此条件,返回 true。

我应该提到我正在寻找 C# 代码,我尝试过但尚未成功,但由于我只编程了两周,我认为这对于一些有经验的程序员来说不会有麻烦。


如请求所示,这是我尝试的内容,我认为它远远不够好,但至少我尝试了。

            if (Title.Contains("Foo") == true && Regex.IsMatch(Title, "^Foo") == true)
        {
            CheckAnd = true;
        }
        else if (Title.Contains("Foo") == true && Regex.IsMatch(Title, "^Foo") == false)
        {
            CheckAnd = false;
        }
        else if (Regex.IsMatch(Title, "^foo"))
        {
            CheckAnd = false;
        }
        else
        {
            CheckAnd = true;
        }

好的,大家差不多了,以下是我从你们所有回答中得到的内容:

if (Title.IndexOf("Foo") == 0 && Title.LastIndexOf("Foo") == 0)
        {
            CheckAnd = true;
        }
        else if (Title.LastIndexOf("Foo") > 0)
        {
            CheckAnd = false;
        }
        else if(Title.Contains("foo") && Title.StartsWith("Foo") == false && PUT CHECK HERE)

我需要检查的最后一件事情是,在最后的else if语句中,所有的foo都是小写的吗?

2
你能展示一下你尝试过的吗? - Bort
1
似乎你想让我们解决一个学校问题。 - Gab
1
哈哈哈,不完全是这样,我正在验证文件名。我只是把编程作为一种爱好,我刚刚开始学习,而且非常喜欢它。 - user1462199
5个回答

17

不想读我的书?这就是答案:

此外,这是最快的解决方案。

public void CheckValidFoo(String Title) {     
    return (Title.LastIndexOf("Foo") <= 0);
}

阅读下面的教程,学习编码逻辑(请原谅这位老人的幽默感)

这个问题可能很旧了,但是为了那些后来发现这个问题,并且对如何从逻辑上概括单词问题感到好奇的人,我将过度分析这个极其简单的作业:

我进行了一系列测试,以查看哪些选项最快 - 这通常有助于我发现自己逻辑上的缺陷。我还将解释我的思考过程,因为在我看来,了解如何将问题简化为其核心逻辑对于实际使用是一件好事。

毕竟,业务需求文档就是需要被简化成功能规格说明书的单词问题(例如架构设计)。

步骤1

消除无关信息
根据给定的要求,小写foo可能重要也可能不重要:没有明确说明不包含foo和不包含Foo的字符串应返回false;也没有明确说明不包含Foo和不包含foo的字符串应返回true。

在完美的世界中,您应该返回以获取更清晰的要求,但在某些情况下,时间不允许。假设有一个最后期限,那么我将继续假设我们关心的是Foo只在句子的第一个位置时为大写,其他时间为小写,因此我们将完全忽略foo,如果“客户”抱怨,请指出缺乏明确性并解释为什么要进行判断调用(如果适用,则保持项目时间和预算)。

步骤2

将逻辑分解为OR / AND组件:
将Foo分成组件可让我们查看单个部分,这可能比查看整体更容易。 因此,如果我们将字符串分解为“Foo之前的东西”(即使是“无”的情况)和“Foo之后的东西”,或者如果没有Foo来分割字符串,那么我们只有一个部分需要考虑。 (我们的大脑一直在这样做 - 这称为模式识别)。

如果无法拆分字符串,因为未找到Foo

     在Foo上分割给我们不超过两个部分:也就是分割后面的内容
      AND(由于先前的检查仅在“之前”找到空字符串,而且在“之后”只有一个“部分”中隐含)      字符串中没有其他地方可以找到Foo

听起来不错吧? 这是100%准确的,但我们可以删减一些笨重的内容并进一步简化它 - 请记住计算机不像人类那样思考,所以我们的心理过程对于他们来说是低效的。

由于完全找不到Foo被认为是有效的,而以Foo开头是有效的,但在字符串中任何其他位置出现Foo都是无效的,我们可以说:

如果未找到Foo
    或
      从第一个位置开始,在字符串中没有找到Foo

听起来很紧凑,对吧?别停下。我们可以做得更好。

如果在开头找到了Foo,我们就没问题了,对吧?因此,“未找到Foo”或“在开头找到了Foo并且在任何其他位置上未找到Foo”可以从更纯粹的逻辑(布尔、真/假、黑白)角度看待:

  • 让FNA =“未在任何地方找到Foo”
  • 让FN1 =“未在位置1找到Foo”
  • 让FN2 =“未在位置1之后找到Foo”
  • 让FF1 =“在位置1找到Foo”
  • 让FF2 =“在位置1之后找到Foo”

因此,我们现在只定义那些确实无效的情况,并将其余标记为有效。我们将使用布尔数学来确定所有用例。

  • 让FNA = 有效
  • 让FN1 = 有效
  • 让FN2 = 有效
  • 让FF1 = 有效
  • 让FF2 = 无效

现在,我们只标记了那些绝对强制返回false的情况,我们可以进行数学运算,看看我们只得到无效/假值的情况。

FNA = FN1和FN2(因此,如果FNA和X = true,则F1和X必须为true,而F2和X也必须为true);

FNA和/或FF1 = true,因此我们知道这4个变量的所有and/or组合= true;这只留下了一个变量需要组合,我们可以很快地看出FF2和任何内容都将始终为false。

因此,换回人类逻辑...看看这个任务变得多么简单?

仅当 在位置1之后找到Foo时才为false

或者,反转布尔(因为要求在有效案例中返回true):

如果从字符串结尾开始扫描直到倒数第二个字符不找到Foo,则字符串有效。

或者,更像计算机思考的方式:

如果从字符串结尾扫描直到第二个到最后一个字符没有找到Foo,则字符串有效

现在,我们无法将其进一步简化。因此,让我们编写这些不同的逻辑部分,并查看它们在实际代码中的表现如何:

using System;

public static class Test
{
public static bool CheckFooTestA(String SearchMe, String[] FindMe)
{
    //split the string like the human eye does and check the count of Foos 
    //and the position of the Foo or Foos to determine our logic:
    string[] v = SearchMe.Split(FindMe, StringSplitOptions.None);
    
         //Foo not found, OR foo found once and was at the beginning of the string
    return (v.Length == 0 || v.Length == 1 && v[0] == String.Empty);
}
public static bool CheckFooTestB(String SearchMe, String[] FindMe)
{
    //scan the way computers or non-speed readers do, and look for the first instance of Foo
    int i = SearchMe.IndexOf(FindMe[0]);

    //Foo not found OR 
    //    foo found at the start of the string 
    //    AND the last Foo found is also at the start of the string
    return (i == -1 || i == 0 && SearchMe.LastIndexOf(FindMe[0]) == 0 );
}
public static bool CheckFooTestC(String SearchMe, String[] FindMe)
{
    //Use the logic we distilled from the word problem to make this single check:
    return (SearchMe.LastIndexOf(FindMe[0]) <= 0);
}
public static void Main()
{
    String[] x = new String[]{
        "Foo foo Foo bar",
        "Foo foo foo bar",
        "foo foo Foo bar",
        "foo foo foo bar",
        "asfda asdfa asf" };
        
    var s = new []{"Foo"};
    var i = 0;
    bool f=false;
    long End = DateTime.Now.Ticks;
    long Start = DateTime.Now.Ticks;
    for (; i < 1000; i++) {
        f = CheckFooTestA(x[i%5],s);
    }
    End = DateTime.Now.Ticks;
    Console.WriteLine((End - Start).ToString() + " ticks (Test A)");

    i = 0;
    f = false;
    End = DateTime.Now.Ticks;
    Start = DateTime.Now.Ticks;
    for (; i < 1000; i++) {
        f = CheckFooTestB(x[i%5],s);
    }
    End = DateTime.Now.Ticks;
    Console.WriteLine((End - Start).ToString() + " ticks (Test B)");
    
    i = 0;
    f = false;
    End = DateTime.Now.Ticks;
    Start = DateTime.Now.Ticks;
    for (; i < 1000; i++) {
        f = CheckFooTestC(x[i%5],s);
    }
    End = DateTime.Now.Ticks;
    Console.WriteLine((End - Start).ToString() + " ticks (Test C)");
}
}
Test.Main();

输出:

260510 ticks (Test A)
117150 ticks (Test B)
76160 ticks (Test C)

结果和结论

与测试B(使用精简逻辑的索引扫描)相比,测试A(基于视觉上的逻辑进行单词切分/计数)运行时间长了超过220%!

测试C是最佳表现者-只需要一次字符串扫描。它的处理时间少于30%(测试A需要超过340%的时间才能完成与测试C相同的工作量)。

希望有学生看到这篇文章,灯泡能亮起来。你总可以想出让东西“工作”的方法,但理解布尔逻辑以及如何将概念简化到其核心可以对您的工作质量产生重大影响。


6
如果我理解正确,这应该可以做到!
    if (testString.IndexOf("Foo") == 0 && testString.LastIndexOf("Foo") == 0)
        // "Foo foo foo"
        return true;
    else if (testString.IndexOf("Foo") == 0 && testString.LastIndexOf("Foo") > 0)
        // "Foo foo Foo"
        return false;
    else if (testString.Contains("foo")  && testString.IndexOf("Foo") > 0)
        // "foo Foo foo" or "foo foo Foo"
        return false; 
    else if (testString.Contains("foo") && !testString.Contains("Foo"))
        // "foo foo foo"
        return true;  

这并没有考虑到包含小写字符串“foo”的情况。 - Bort
那么为什么最后一个检查不起作用呢?应该遵循什么规则? - Jason De Oliveira
字符串包含foo,但不以Foo开头,所有foo的实例应为小写。 --> 字符串中只有小写的foo,对吧? - Jason De Oliveira
是的?我有什么遗漏吗?:),不过我暂时将其标记为答案了,但是我该如何进行最后的检查呢? - user1462199
好的,else if (testString.Contains("foo") && !testString.Contains("Foo")) 确切地验证了这一点。字符串中只存在 "foo" 而不是 "Foo"。 - Jason De Oliveira
显示剩余3条评论

2

这将返回true(因为它包含单词Foo),然后返回false(因为Foo不在句子开头)。

        string word = "I am a string i contain Foo, aint that nice?";
        bool conts = word.Contains("Foo");
        int pos = word.IndexOf("Foo");                 
        if (conts)
        {
            if (pos != 0)
            {
                // do something
            }

        }

字符串 "Fun at the park is Foo, coo." 也会被验证为正确,但实际上是不正确的。可以使用 String.CompareOrdinal 方法来验证字符串的开头部分,使用 (string, int string, int, int) 的重载形式。 - Joshua
@Joshua 非常正确。我没有想到 :) - Thousand
哦,编辑得很有趣。你可以通过一次调用 LastIndexOf 来结合整个部分。如果返回值是 -1,则表示字符串未找到;如果返回值为 0,则表示它是正确的情况并且是字符串的开头;如果返回值大于 0,则无法满足最后一部分要求:“它应该是唯一以大写字母开头的 Foo”。 - Joshua

1

如果我正确理解问题,这种方法应该有效。

    public bool ContainsFoo(string s)
    {
        bool result = true;

        if (s.IndexOf("Foo") > 0)
        {
            result = false;
        }
        else if (s.LastIndexOf("Foo") > 0)
        {
            result = false;
        }
        return result;
    }

如果我有什么误解,请告诉我。


我认为else部分是多余的。如果第一个出现的索引大于0,则最后一个出现的索引也大于0。 - Forte L.
@ForteL。我正在使用else来检查字符串是否包含另一个“Foo”,如果是,则应返回false。 - MAV
是的,但请注意,即使字符串根本不包含“Foo”,您的方法也会返回true。 - Forte L.
如果字符串中根本没有“Foo”,我确实会检查if和else。如果它不包含“Foo”,则返回true,因为OP说应该这样做。“在字符串包含foo但不以Foo开头的情况下,所有foo的实例都应为小写。”- 我假设它是否包含“foo”并不重要。 - MAV
我明白这很重要,如果它包含“foo”。如果没有,那么你的代码就没问题。 - Forte L.

1
请参考 String.IndexOf 方法:

http://msdn.microsoft.com/en-us/library/k8b1470s.aspx

搜索区分大小写,因此只需查找大写字母单词(例如:“Foo”)。如果IndexOf返回0,则该单词位于第一个位置。
编辑:这是我看了你的代码后会做的方式。
//changed to check for lowercase foo
if ((Title.StartsWith("Foo") && Title.LastIndexOf("Foo") == 0) 
|| (Title.Contains("foo") && !Title.StartsWith("foo")))
{
    CheckAnd = true;
}
else
    CheckAnd = false;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接