2015-11-17 3 views
0

Я довольно новичок в кодировании, поэтому, я думаю, я не вижу очевидного ответа, поэтому я сожалею, если это глупый вопрос, но я действительно застрял здесь. Я пытаюсь сравнить два набора триграмм из двух разных текстов (A и B). Если в B нет триграмм в B, то я бы сказал, что эти два текста отличаются друг от друга, по крайней мере, для моей нынешней цели. Я использую Nuve для извлечения триграмм.Сравнение триграмм

До сих пор у меня есть это:

 var paragraph = "This is not a phrase. This is not a sentence."; 
     var paragraph2 = "This is a phrase. This is a sentence. This have nothing to do with sentences."; 
     ITokenizer tokenizer = new ClassicTokenizer(true); 
     SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer); 
     var sentences = segmenter.GetSentences(paragraph); 
     ITokenizer tokenizer2 = new ClassicTokenizer(true); 
     SentenceSegmenter segmenter2 = new TokenBasedSentenceSegmenter(tokenizer2); 
     var sentences2 = segmenter2.GetSentences(paragraph2); 


     var extractor = new NGramExtractor(3); 
     var grams1 = extractor.ExtractAsList(sentences); 
     var grams2 = extractor.ExtractAsList(sentences2); 

     var nonintersect = grams2.Except(grams1); 


     foreach (var nGram in nonintersect) 
     { 
      var current = nGram; 
      bool found = false; 
      foreach (var n in grams2) 
      { 

       if (!found) 
       { 
        if (n == current) 
        { 
         found = true; 

        } 
       } 
      } 
      if (!found) 
      { 
       var result = current; 
       string finalresult = Convert.ToString(result); 
       textBox3.AppendText(finalresult+ "\n"); 

      } 

Таким образом, я надеюсь получить предложения, которые, находясь в B, нет в A (т.е. все предложения от B в примере), но теперь Мне нужно было бы сравнить каждую триграмму от B до каждой триграммы от A, чтобы увидеть, действительно ли предложения действительно отличаются друг от друга. Я пытался сделать это с другим вложенным Еогеаспом, но я получаю просто бессмысленные данные следующим образом:

foreach (var sentence2 in sentences2) 
     { 
      var actual = sentence2; 
      bool found1 = false; 

      foreach (var sentence in sentences) 
      { 

       if (!found1) 
       { 
        if (actual == sentence) 
        { 
        found1 = true; 
        } 
       } 

      } 

      if (!found1) 
      { 

        string finalresult= Convert.ToString(actual); 
        textBox3.AppendText(finalresult+ "\n"); 

      } 

     } 

Делая это, я стараюсь, чтобы проверить, если триграммы из каждого предложения в B равны триграммы от каждого предложения в A и, если они есть, то textBox3 будет пустым.

Вкратце, я пытаюсь закодировать что-то похожее на Ferret, но для C# и только для сравнения двух заданных простых текстов. Насколько я знаю, ничего подобного уже не было сделано для C#.

Любая помощь или подсказка будут действительно оценены. Благодаря!

+0

На первый взгляд 'found =! Found' выглядит подозрительно - это задание, которое переворачивается' found'. Изменить это на 'found ==! Found' по-прежнему не имеет смысла, потому что это всегда оценивает' false'. Вероятно, вы хотели использовать 'if (! Found)' - ', если найдено не верно, а затем ...'. –

+0

Также обратите внимание, что 'List ' имеет метод 'Contains'. В качестве альтернативы вы можете использовать метод Linq 'Any', который работает со всем перечислимым - списками, массивами, наборами и т. Д. Если вы должны использовать цикл, помните, что вы можете выйти из него, как только найдете совпадение с ключевым словом 'break', что исключает необходимость проверки' найденного' в цикле. –

+0

Хорошо, спасибо Питер. Предположим, что мы используем 'if (! Found)' then. – JuanLuis

ответ

1

Сопоставляя тела текста

Сравнивая два тела текста и пометив их как одинаковые, если они имеют по крайней мере одно предложение на уровне триграмма общего довольно прямолинейно:

public bool AreTextsSimilar(string a, string b) 
{ 
    // We can reuse these objects - they could be stored in member fields: 
    ITokenizer tokenizer = new ClassicTokenizer(true); 
    SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer); 
    NGramExtractor trigramExtractor = new NGramExtractor(3); 

    IEnumerable<string> sentencesA = segmenter.GetSentences(a); 
    IEnumerable<string> sentencesB = segmenter.GetSentences(b); 

    // The order of trigrams doesn't matter, so we'll fetch them as sets instead, 
    // to make comparisons between their elements more efficient: 
    ISet<NGram> trigramsA = trigramExtractor.ExtractAsSet(sentencesA); 
    ISet<NGram> trigramsB = trigramExtractor.ExtractAsSet(sentencesB); 

    // 'Intersect' returns all elements that are found in both collections: 
    IEnumerable<NGram> sharedTrigrams = trigramsA.Intersect(trigramsB); 

    // 'Any' only returns true if the collection isn't empty: 
    return sharedTrigrams.Any(); 
} 

Без Linq методы (Intersect, Any), эти последние две строки могут быть реализованы в виде петли:

foreach (NGram trigramA in trigramsA) 
    { 
     // As soon as we find a shared sentence trigram we can conclude that 
     // the two bodies of text are indeed similar: 
     if (trigramsB.Contains(trigramA)) 
      return true; 
    } 
    return false; 
} 

Приговоры без общего слова триграмм

Получение списка всех предложений, которые не разделяют триграмм слово уровня занимает немного больше работы:

public IEnumerable<string> GetUniqueBSentences(string a, string b) 
{ 
    // We can reuse these objects - they could be stored in member fields: 
    ITokenizer tokenizer = new ClassicTokenizer(true); 
    SentenceSegmenter segmenter = new TokenBasedSentenceSegmenter(tokenizer); 
    NGramExtractor trigramExtractor = new NGramExtractor(3); 

    IEnumerable<string> sentencesA = segmenter.GetSentences(a); 
    IEnumerable<string> sentencesB = segmenter.GetSentences(b); 

    ITokenizer wordTokenizer = new ClassicTokenizer(false); 
    foreach (string sentenceB in sentencesB) 
    { 
     IList<string> wordsB = wordTokenizer.Tokenize(sentenceB); 
     ISet<NGram> wordTrigramsB = trigramExtractor.ExtractAsSet(wordsB); 

     bool foundMatchingSentence = false; 
     foreach (string sentenceA in sentencesA) 
     { 
      // This will be repeated for every sentence in B. It would be more efficient 
      // to generate trigrams for all sentences in A once, before we enter these loops: 
      IList<string> wordsA = wordTokenizer.Tokenize(sentenceA); 
      ISet<NGram> wordTrigramsA = trigramExtractor.ExtractAsSet(wordsA); 

      if (wordTrigramsA.Intersect(wordTrigramsB).Any()) 
      { 
       // We found a sentence in A that shares word-trigrams, so stop comparing: 
       foundMatchingSentence = true; 
       break; 
      } 
     } 

     // No matching sentence in A? Then this sentence is unique to B: 
     if (!foundMatchingSentence) 
      yield return sentenceB; 
    } 
} 

Видимо segmenter также возвращает дополнительную пустую фразу, которую вы можете хотите отфильтровать (или выяснить, как предотвратить выполнение segmenter).

Я уверен, что приведенный выше код можно оптимизировать, если производительность является проблемой, но я оставлю это до вас.

+0

Большое спасибо Pieter, он отлично работает. – JuanLuis

Смежные вопросы