我试图在c#中找到一个库,可以帮助我做词性标记,从句子中识别一个名词,但无济于事。因此,我决定将字符串中的单词与我下载的文本文件中的名词列表进行比对。我的代码假设句子中的第一个名词是动词所指的名词,我这样做是因为网站上留下的大多数评论都不是由很多单词组成的。这里我尝试将文本分割成一个数组然后遍历n。txt文件中的每个名词,看看我的字符串是否存在。我的代码如下,我只是想返回The first noun found
或No noun detected
作为我的方法的返回类型。
string DetectNoun(string param){
//split the input parameter into words based on spaces
string[] words=param.ToLower().Split(" ");
//read all the nouns in the text file into an array:NB all nouns are in lower case
string[] allNouns=File.ReadAllLines("Nouns.txt");
//loop through each noun in the array and check if any exists in our input parameter
int j=0;
for(int i=0;i>allNouns.Length;i++){
if(allNouns[i]==words[j++]){
//return this word as the noun found
return allNouns[i];
}
}
//if no match was found return no noun detected
return "No noun detected";
}
以Samsung Television, No manual, Box included
为样本输入进行上述测试。尽管电视在我刚下载的名词文本文件中,它仍然返回No noun was detected
。
您的原始代码有几个问题:
-
您按空格分隔,因此在您的情况下,您得到(例如)
television,
,在单词列表中使用逗号。当比较时,您将television
与television,
进行比较,因此它不匹配。 -
您正在使用
==
进行比较,这是"令人困惑的";在比较字符串时,应该使用正确的字符串比较器。 -
你的
for
循环被打破了,你只是比较索引与索引(第一个单词与第一个名词,第二个单词与第二个名词,等等)…此外,如果您的名词列表小于单词列表,这将引发IndexOutOfRange
异常
要解决所有这些问题:
-
在分割之前,从字符串中删除所有不想要的字符。我建议使用regex (
Regex.Replace(input, @"[^a-zA-Zd ]", "")
),但您需要检查它是否适合您的输入(特别是如果接收非a- z字母数字字符,如重音或变音符等) -
StringComparer使用。OrdinalIgnoreCase或StringComparison。OrdinalIgnoreCase而不是
ToLower()
。ToLower()
通常不是正确的方式,特别是在处理英语以外的文化时 -
我会使用Linq并从中生成一行代码:
words.FirstOrDefault(x => allNouns.Contains(x, StringComparer.OrdinalIgnoreCase);
如果words
中的no字包含在allNouns
中,则返回null
,否则返回第一个匹配。
把它们放在一起:
string DetectNoun(string param){
string[] words = Regex.Replace(param, @"[^a-zA-Zd ]", "").Split(' ');
// You should cache this somewhere if you plan to call this many times,
// but I'll leave that up to you
string[] allNouns=File.ReadAllLines("Nouns.txt");
return words.FirstOrDefault(x => allNouns.Contains(x, StringComparer.OrdinalIgnoreCase))
?? "No noun detected";
}