.net 使用LINQ统计文本字段中的单词出现次数

.net 使用LINQ统计文本字段中的单词出现次数,.net,linq,pattern-matching,.net,Linq,Pattern Matching,如何使用LINQ获取数据库文本字段中单词的出现次数 关键字令牌示例:ASP.NET 编辑4: 数据库记录: 记录1:[TextField]=“废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话 记录2:[TextField]=“废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废

如何使用LINQ获取数据库文本字段中单词的出现次数

关键字令牌示例:ASP.NET

编辑4:

数据库记录:

记录1:[TextField]=“废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话

记录2:[TextField]=“废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话废话

记录3:[TextField]=“BlahASP.NETBlahASP.NETBlahASP.NETbliASP.NETbliASP.NETbluASP.NETyopASP.NET

所以

记录1包含4个出现的“ASP.NET”关键字

记录2包含2个出现的“ASP.NET”关键字

记录3包含7个出现的“ASP.NET”关键字

集合提取IList(按字数降序排列)

  • 记录3
  • 记录1
  • 记录2
LinqToSQL应该是最好的,但LinqToObject也是:)


注意:ASP.NET关键字的“.”没有问题(如果是这个问题,这不是目标)

您可以
Regex.Matches(input,pattern)。Count
或执行以下操作:

int count = 0; int startIndex = input.IndexOf(word);
while (startIndex != -1) { ++count; startIndex = input.IndexOf(word, startIndex + 1); }
在这里使用LINQ会很难看

使用String.Split()将字符串转换为一个单词数组,然后使用LINQ筛选此列表,仅返回所需的单词,然后检查结果的计数,如下所示:

myDbText.Split(' ').Where(token => token.Equals(word)).Count();

编辑2:我看到你更新了问题,改变了一点,每个单词的字数是多少?试试这个:

string input = "some random text: how many times does each word appear in some random text, or not so random in this case";
char[] separators = new char[]{ ' ', ',', ':', ';', '?', '!', '\n', '\r', '\t' };

var query = from s in input.Split( separators )
            where s.Length > 0
            group s by s into g
            let count = g.Count()
            orderby count descending
            select new {
                Word = g.Key,
                Count = count
            };

由于您需要的单词中可能包含“.”(例如“ASP.NET”),我已将其从分隔符列表中排除,不幸的是,这将污染某些单词,因为“等等等等等等。等等等等等等。”将显示“等等”的计数为3,“等等。”的计数为2。你需要考虑一下你想要什么样的清理策略,例如,如果“.”两边都有一个字母,它就算作一个单词的一部分,否则它就是空白。这种逻辑最好用一些正则表达式来完成。

正则表达式可以很好地处理这个问题。您可以使用
\b
元字符锚定单词边界,并转义关键字以避免意外使用特殊正则表达式字符。它还处理尾随句点、逗号等情况

string[] records =
{
    "foo ASP.NET bar", "foo bar",
    "foo ASP.NET? bar ASP.NET",
    "ASP.NET foo ASP.NET! bar ASP.NET",
    "ASP.NET, ASP.NET ASP.NET, ASP.NET"
};
string keyword = "ASP.NET";
string pattern = @"\b" + Regex.Escape(keyword) + @"\b";
var query = records.Select((t, i) => new
            {
                Index = i,
                Text = t,
                Count = Regex.Matches(t, pattern).Count
            })
            .OrderByDescending(item => item.Count);

foreach (var item in query)
{
    Console.WriteLine("Record {0}: {1} occurrences - {2}",
        item.Index, item.Count, item.Text);
}

瞧!:)

我知道这比最初提出的问题要多,但它仍然与主题匹配,我将它包括在后面搜索此问题的其他人的列表中。这不需要在搜索的字符串中匹配整个单词,但是可以通过Ahmad的帖子中的代码轻松地进行修改

//use this method to order objects and keep the existing type
class Program
{
  static void Main(string[] args)
  {
    List<TwoFields> tfList = new List<TwoFields>();
    tfList.Add(new TwoFields { one = "foo ASP.NET barfoo bar", two = "bar" });
    tfList.Add(new TwoFields { one = "foo bar foo", two = "bar" });
    tfList.Add(new TwoFields { one = "", two = "barbarbarbarbar" });

    string keyword = "bar";
    string pattern = Regex.Escape(keyword);
    tfList = tfList.OrderByDescending(t => Regex.Matches(string.Format("{0}{1}", t.one, t.two), pattern).Count).ToList();

    foreach (TwoFields tf in tfList)
    {
      Console.WriteLine(string.Format("{0} : {1}", tf.one, tf.two));
    }

    Console.Read();
  }
}


//a class with two string fields to be searched on
public class TwoFields
{
  public string one { get; set; }
  public string two { get; set; }
}
//使用此方法对对象进行排序并保留现有类型
班级计划
{
静态void Main(字符串[]参数)
{
List tfList=新列表();
添加(新的两个字段{one=“foo ASP.NET barfoo bar”,two=“bar”});
添加(新的两个字段{one=“foo-bar-foo”,two=“bar”});
添加(新的两个字段{one=”“,two=“BarbarBar”});
string关键字=“bar”;
字符串模式=Regex.Escape(关键字);
tfList=tfList.OrderByDescending(t=>Regex.Matches(string.Format(“{0}{1}”,t.one,t.two),pattern.Count).ToList();
foreach(tfList中的两个字段tf)
{
WriteLine(string.Format(“{0}:{1}”,tf.one,tf.two));
}
Console.Read();
}
}
//具有两个要搜索的字符串字段的类
公共类TwoFields
{
公共字符串one{get;set;}
公共字符串二{get;set;}
}

//同上,但使用多个关键字
班级计划
{
静态void Main(字符串[]参数)
{
List tfList=新列表();
添加(新的两个字段{one=“oneone,two;三四五”,two=“bar”});
添加(新的两个字段{one=“一两三”,two=“bar”});
添加(新的两个字段{one=“一二三四五五”,two=“bar”});
字符串关键字=“五一”;
string关键字clean=Regex.Replace(关键字@“\s+”,“”)。Trim();//用一个空格替换多个空格
string pattern=Regex.Escape(关键字clean).Replace(“\\”,“|”);//转义特殊字符并将空格替换为“或”
tfList=tfList.OrderByDescending(t=>Regex.Matches(string.Format(“{0}{1}”,t.one,t.two),pattern.Count).ToList();
foreach(tfList中的两个字段tf)
{
WriteLine(string.Format(“{0}:{1}”,tf.one,tf.two));
}
Console.Read();
}
}
公共类TwoFields
{
公共字符串one{get;set;}
公共字符串二{get;set;}
}

这个词后面可以跟一个句号,也可以跟一个大写字母。您是否正在尝试使用Linq to SQL在数据库端执行此操作?或者您正在处理客户端上的数据子集(即,通过集合对对象执行Linq)?我已经获取了包含关键字的数据子集。所以现在我正在使用Linq To Object over collection(是的:),但我认为最好是构建一个多功能LinqToSQL查询,以提高性能。。。与其预先获取包含每个关键字的数据子集,然后在内存中执行该操作,不如为其编写一个数据库函数,我无法想象L2S是否足够聪明,能够在SQL中构建类似的内容。SQL在字符串操作方面相当差,它的sting函数非常原始,最好将文本作为文本并在代码中进行处理。如果文本中的单词是have,而您没有,该怎么办?如果您的解决方案可行,这将取决于要求。我并不需要特定单词的计数,但根据每个记录中特定单词计数的最大计数排序的数据提取也适用于['],假设您希望排除引号,除非它们是单词的一部分。这个问题最好分为另一个问题,因为你需要最好的正则表达式来提取单词(如果还没有任务的话)
//same as above, but uses multiple keywords
class Program
{
  static void Main(string[] args)
  {
    List<TwoFields> tfList = new List<TwoFields>();
    tfList.Add(new TwoFields { one = "one one, two; three four five", two = "bar" });
    tfList.Add(new TwoFields { one = "one one two three", two = "bar" });
    tfList.Add(new TwoFields { one = "one two three four five five", two = "bar" });

    string keywords = " five one    ";
    string keywordsClean = Regex.Replace(keywords, @"\s+", " ").Trim(); //replace multiple spaces with one space

    string pattern = Regex.Escape(keywordsClean).Replace("\\ ","|"); //escape special chars and replace spaces with "or"
    tfList = tfList.OrderByDescending(t => Regex.Matches(string.Format("{0}{1}", t.one, t.two), pattern).Count).ToList();

    foreach (TwoFields tf in tfList)
    {
      Console.WriteLine(string.Format("{0} : {1}", tf.one, tf.two));
    }

    Console.Read();
  }
}

public class TwoFields
{
  public string one { get; set; }
  public string two { get; set; }
}