【问题标题】:Checking syntax of strings - C#检查字符串的语法 - C#
【发布时间】:2017-09-01 18:27:19
【问题描述】:

我正在尝试找出如何在 C# 中分析句子的语法。 就我而言,我有一个语法,每个句子都必须遵循。 语法如下所示:

“B”是“C”。

每个句子必须包含五个单词。我的句子的第一个单词必须是'A',第三个'is'和第四个'a'。

现在我想检查一个测试句是否符合我的语法。

测试句:

狗不是猫。

在这个例子中,测试句是错误的,因为第四个单词是“no”而不是“a”,它应该基于语法。

我读到了 LINQ,我可以在其中查询包含指定单词集的句子。

代码如下所示:

//Notice the third sentence would have the correct syntax
string text = "A Dog is no Cat. My Dog is a Cat. A Dog is a Cat.";

//Splitting text into single sentences
string[] sentences = text.Split(new char[] { '.'});

//Defining the search terms
string[] wordToMatch ={"A", "is"};

//Find sentences that contain all terms I'm looking for
var sentenceQuery = from sentence in sentences
        let w = sentence.Split(new Char[] {'.'})
        where w.Distinct().Intersect(wordsToMatch).Count == wordsToMatch.Count()
        select sentence;

使用此代码,我可以检查句子是否包含我要查找的术语,但问题是它没有检查句子中单词的位置。 有没有办法我也可以检查位置,或者更好的方法来检查 C# 句子的语法?

【问题讨论】:

  • "intersect" 没有说明单词在列表中的位置,因此不会起作用。您想要做的是拆分输入字符串并以某种方式编写与模式匹配的方法 - 通过硬编码 if (words[0] != "A") return false; 等,或者通过给它一组规则 - 可能是像 { int Index; string RequiredWord; } 这样的对象列表.您的第一句话令人震惊,但您的实际要求是相当适度和合理的。更新如果我有更多的感觉,我会直接进入德米特里的正则表达式想法。您的代码也可以构建正则表达式字符串(那么您有 3 个问题)
  • “A Dog42 is a Cat17”是一个有效的语法吗?
  • @AleksAndreev 在这种情况下是的。我不是要检查这句话是否有意义。只是想找出句子是否包含我指定的语法

标签: c# string linq string-comparison


【解决方案1】:

尝试使用正则表达式,如下所示:

using System.Text.RegularExpressions;

...

string source = "A Dog is no Cat.";

bool result = Regex.IsMatch(source, @"^A\s+[A-Za-z0-9]+\s+is\s+a\s+[A-Za-z0-9]+\.$");  

模式说明:

 ^           - start of the string (anchor)
 A           - Letter A 
\s+          - one or more whitelines (spaces)
[A-Za-z0-9]+ - 1st word (can contain A..Z, a..z letters and 0..9 digits)
\s+          - one or more whitelines (spaces) 
 is          - is 
\s+          - one or more whitelines (spaces) 
 a           - a
\s+          - one or more whitelines (spaces)
[A-Za-z0-9]+ - 2nd word (can contain A..Z, a..z letters and 0..9 digits)
\.           - full stop 
 $           - end of the string (anchor)

您可以稍微修改代码并获得实际的第一个和第二个字符串的值:

string source = "A Dog is a Cat."; // valid string

string pattern =
   @"^A\s+(?<First>[A-Za-z0-9]+)\s+is\s+a\s+(?<Second>[A-Za-z0-9]+)\.$";

var match = Regex.Match(source, pattern); 

if (match.Success) {
  string first = match.Groups["First"].Value;   // "Dog"
  string second = match.Groups["Second"].Value; // "Cat"

  ... 
}  

【讨论】:

  • 怎么样:'A 7 是一个数字'?
  • @sTrenat:在我当前的代码中,输入 " A 7 is a number."invalid:它以 空格(不是 A)和 @ 开头987654326@ 不是一个词。如果这样的字符串应该是有效的,那么模式应该是@"^\s*A\s+[A-Za-z0-9]+\s+is\s+a\s+[A-Za-z0-9]+\.$"
  • 我知道它不会,只是想得到一些数字的例子:) 谢谢
  • @sTrenat:我在评论中看到"A Dog42 is a Cat17." 应该是一个有效的输入,我已经编辑了模式(添加了数字)。谢谢!
  • 我想知道为什么 7 不起作用? [A-Za-z0-9] 是否意味着单词必须以大写字母开头,后跟小写字母,最后也可以有数字?这就是我理解指定模式的方式: valid=Max12, invalid=max12, invalid=mAx12, invalid=12Max, invalid=7 ;我说的对吗?
【解决方案2】:

正则表达式可以解决这个问题,并且是最简洁的,但可能不是最易读的解决方案。这是一个简单的方法,如果句子有效,它将返回 true:

private bool IsSentenceValid(string sentence)
{
    // split the sentence into an array of words
    char[] splitOn = new char[] {' '};
    string[] words = sentence.ToLower().Split(splitOn); // make all chars lowercase for easy comparison

    // check for 5 words.
    if (words.Length != 5)
        return false;

    // check for required words
    if (words[0] != "a" || words[2] != "is" || words[3] != "a")
        return false;

    // if we got here, we're fine!
    return true;
}

【讨论】:

    【解决方案3】:

    只是想抛出想法。我会为此写三个类:

    1. SentenceManager:获取字符串作为句子,并有一个公共方法public string GetWord(word_index)。例如,GetWord(3) 将返回句子中的第三个单词,该单词已提供给类构造函数。

    2. SentenceSyntax:在这堂课上,你可以说出你的句子必须有多少个单词。必须知道哪些单词,您也可以设置这些单词的索引。

    3. SyntaxChecker:该类获取一个SentenceSyntax 对象和一个SentenceManager 对象,并有一个名为Check 的函数,如果语法与句子匹配则返回true。

    请记住,有成千上万种方法可以让某件事情发挥作用。但是有一些方法可以做到这一点。

    【讨论】:

      【解决方案4】:

      您绝对应该使用正则表达式或类似 Dmitry has answered 的东西来完成此操作

      只是为了好玩,我想按照你的方式去做。如果我发疯了,我会这样做:)

      //Notice the third sentence would have the correct syntax
      string text = "A Dog is no Cat.My Dog is a Cat.A Dog is a Cat.";
      
      //Splitting text into single sentences
      string[] sentences = text.Split(new char[] { '.' });
      
      string[] wordsToMatch = { "A", "*", "is", "a", "*" };
      
      var sentenceQuery = from sentence in sentences
                          let words = sentence.Split(' ')
                          where words.Length == wordsToMatch.Length && 
                                wordsToMatch.Zip(words, (f, s) => f == "*" || f == s).All(p => p)
                          select sentence;
      

      使用此代码,您还可以获得灵活性,例如不区分大小写的比较,以及修剪单词周围的空格等 - 当然您必须为此编写代码

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-13
        • 2018-04-29
        • 2014-03-28
        • 1970-01-01
        • 2015-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多