Advertisement
Guest User

Untitled

a guest
Oct 16th, 2019
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 26.06 KB | None | 0 0
  1. public class NewFieldTaggingManager
  2.     {
  3.         public const string Other = "<Other>";
  4.  
  5.         private class IndexRange
  6.         {
  7.             public int Start { get; }
  8.             public int Length { get; set; }
  9.  
  10.             public IndexRange(int start, int length)
  11.             {
  12.                 Start = start;
  13.                 Length = length;
  14.             }
  15.             public override string ToString() => $"{Start};{Length}";
  16.         }
  17.  
  18.         class WordsPhrase
  19.         {
  20.             public WordsPhrase Parent { get; set; }
  21.  
  22.             public string Phrase { get; }
  23.  
  24.             public double Weight { get; }
  25.  
  26.             public string Label { get; }
  27.  
  28.             public List<Token> Tokens { get; }
  29.  
  30.             public List<Tuple<string, double>> TopLabels { get; }
  31.  
  32.             //public double ResultKoef { get; set; }
  33.  
  34.             public CompareStatus Status { get; set; }
  35.  
  36.             public int Generation { get; set; }
  37.  
  38.             public WordsPhrase(string phrase, string label, double weight, List<Token> tokens, List<Tuple<string, double>> topLabels)
  39.             {
  40.                 Phrase = phrase;
  41.                 Label = label;
  42.                 Weight = weight;
  43.                 Tokens = tokens;
  44.                 TopLabels = topLabels;
  45.             }
  46.  
  47.             public WordsPhrase Clone()
  48.             {
  49.                 return (WordsPhrase)MemberwiseClone();
  50.             }
  51.  
  52.             //public override string ToString() => $"{Phrase} ({ResultKoef:N3}) => {Label} ({Weight:N3})";
  53.             public override string ToString() => $"{Phrase} => {Label} ({Weight:N3})";
  54.         }
  55.  
  56.         /// <summary>
  57.         /// Выполняет определение принадлежности токенов к определенной сущности.
  58.         /// </summary>
  59.         /// <param name="tokens"></param>
  60.         public void Parse(List<Token> tokens, ClassifierEngineData engineData)
  61.         {
  62.             var groups = TagTokenHelper.GetMaxGroups(tokens,
  63.                 t => t.TokenType == TokenType.Undefined,
  64.                 t => t.TokenType == TokenType.Ignore
  65.             );
  66.             foreach (var group in groups)
  67.             {
  68.                 // фразы в скобочках обрабатываем отдельно
  69.                 if (group.Count > 1 && IsGroupInParentheses(group, tokens))
  70.                     AnalizeAndTagSentenceInParentheses(group, tokens, engineData);
  71.                 else
  72.                     AnalizeAndTagSentence(group, tokens, engineData);
  73.             }
  74.         }
  75.  
  76.         /// <summary>
  77.         /// Проверяет находится ли группа в скобках.
  78.         /// </summary>
  79.         /// <param name="group"></param>
  80.         /// <param name="tokens"></param>
  81.         /// <returns></returns>
  82.         private bool IsGroupInParentheses(List<Token> group, List<Token> tokens)
  83.         {
  84.             // находим левый токен и пропускаем игнорируемые
  85.             int firstGroupTokenIdx = tokens.IndexOf(group[0]);
  86.             while (firstGroupTokenIdx - 1 >= 0 && tokens[firstGroupTokenIdx - 1].TokenType == TokenType.Ignore)
  87.                 firstGroupTokenIdx--;
  88.  
  89.             if (firstGroupTokenIdx == 0)
  90.                 return false;
  91.  
  92.             // находим правый токен и пропускаем игнорируемые
  93.             int lastGroupTokenIdx = tokens.IndexOf(group[group.Count - 1]);
  94.             while (lastGroupTokenIdx + 1 < tokens.Count && tokens[lastGroupTokenIdx + 1].TokenType == TokenType.Ignore)
  95.                 lastGroupTokenIdx++;
  96.  
  97.             if (lastGroupTokenIdx == tokens.Count - 1)
  98.                 return false;
  99.  
  100.             // проверяем что дальше стоят скобочки
  101.             if (tokens[firstGroupTokenIdx - 1].Word == "(" && tokens[lastGroupTokenIdx + 1].Word == ")")
  102.                 return true;
  103.  
  104.             return false;
  105.         }
  106.  
  107.         /// <summary>
  108.         /// Выполняет анализ списка токенов, которые расположены в скобках и являются (скорей всего) одной сущностью.
  109.         /// </summary>
  110.         /// <param name="group"></param>
  111.         /// <param name="tokens"></param>
  112.         private void AnalizeAndTagSentenceInParentheses(List<Token> group, List<Token> tokens, ClassifierEngineData engineData)
  113.         {
  114.             WordsPhrase phrase = TokensToPhrase(group, tokens, engineData);
  115.  
  116.             group.ForEach(t => { t.MatchWord = phrase.TopLabels[0].Item1; t.TokenType = TokenType.Param; });
  117.         }
  118.  
  119.         /// <summary>
  120.         /// Генерирует фразу со всеми характеристиками из списка токенов.
  121.         /// </summary>
  122.         /// <param name="phraseTokens"></param>
  123.         /// <returns></returns>
  124.         private WordsPhrase TokensToPhrase(List<Token> phraseTokens, List<Token> sourceTokens, ClassifierEngineData engineData)
  125.         {
  126.             int takeCount = phraseTokens.Count;
  127.             List<Token> allPhraseTokens = GetAllTokensWithSeparators(phraseTokens, sourceTokens);
  128.             string sumWord = TagTokenHelper.RecollectTagsWord(allPhraseTokens);
  129.             var res = engineData.Predict(sumWord);
  130.  
  131.             double degreOfConfidence = res.Weight; //GetDegreeOfConfidence(res.Score);
  132.             List<Tuple<string, double>> topCfSum = GetTopFields(engineData.AllLabels, res.Score, 3);
  133.  
  134.             WordsPhrase phrase = new WordsPhrase(sumWord, res.Result, res.Weight, phraseTokens, topCfSum);
  135.             //phrase.ResultKoef = CalcResultCoef(phrase);
  136.             return phrase;
  137.         }
  138.  
  139.         /// <summary>
  140.         /// Выполняет анализ списка токенов для определения принадлежности к сущности.
  141.         /// </summary>
  142.         /// <param name="tokens"></param>
  143.         private void AnalizeAndTagSentence(List<Token> tokens, List<Token> sourceTokens, ClassifierEngineData engineData)
  144.         {
  145.             List<WordsPhrase> phrases = GenerateInitialPhrases(tokens, sourceTokens, engineData);
  146.  
  147.             int gen = 1;
  148.             bool done = false;
  149.             while (gen <= 5 && !done)
  150.             {
  151.                 phrases = ProcessExpandPhrases(phrases, sourceTokens, engineData, gen, out done);
  152.                 gen++;
  153.             }
  154.  
  155.             foreach (var phrase in phrases)
  156.             {
  157.                 foreach (var token in phrase.Tokens)
  158.                 {
  159.                     if (phrase.Label != Other && phrase.Weight > threshold)
  160.                     {
  161.                         token.TokenType = TokenType.Param;
  162.                         token.MatchWord = phrase.Label;
  163.                     }
  164.                     else
  165.                     {
  166.                         //token.MatchWord = "Other";
  167.                     }
  168.                 }
  169.             }
  170.         }
  171.  
  172.         private List<WordsPhrase> ProcessExpandPhrases(List<WordsPhrase> phrases, List<Token> sourceTokens, ClassifierEngineData engineData, int generation, out bool done)
  173.         {
  174.             List<WordsPhrase> childPhrases = new List<WordsPhrase>();
  175.             bool newPhrasesGenerated = false;
  176.             for (int i = 0; i < phrases.Count; i++)
  177.             {
  178.                 var phrase = phrases[i];
  179.                 if (phrase.Generation < generation - 1)
  180.                 {
  181.                     childPhrases.Add(phrase);
  182.                     continue;
  183.                 }
  184.  
  185.                 bool anyChildrenAdded = false;
  186.  
  187.                 if (i > 0 && (generation == 1 || phrases[i - 1].Label == Other))
  188.                 {
  189.                     WordsPhrase combinedToLeft = ConcatenatePhrases(phrases[i - 1], phrase, sourceTokens, engineData);
  190.                     var compareStatus = ComparePhrases(combinedToLeft, phrase);
  191.                     combinedToLeft.Parent = phrase;
  192.                     combinedToLeft.Status = compareStatus;
  193.                     combinedToLeft.Generation = generation;
  194.                     childPhrases.Add(combinedToLeft);
  195.                     anyChildrenAdded = true;
  196.                 }
  197.  
  198.                 if (i < phrases.Count - 1 && (generation == 1 || phrases[i + 1].Label == Other))
  199.                 {
  200.                     WordsPhrase combinedToRight = ConcatenatePhrases(phrase, phrases[i + 1], sourceTokens, engineData);
  201.                     var compareStatus = ComparePhrases(combinedToRight, phrase);
  202.                     combinedToRight.Parent = phrase;
  203.                     combinedToRight.Status = compareStatus;
  204.                     combinedToRight.Generation = generation;
  205.                     childPhrases.Add(combinedToRight);
  206.                     anyChildrenAdded = true;
  207.                 }
  208.  
  209.                 if (!anyChildrenAdded)
  210.                     childPhrases.Add(phrase);
  211.                 else
  212.                     newPhrasesGenerated = true;
  213.             }
  214.  
  215.             if (!newPhrasesGenerated)
  216.             {
  217.                 done = true;
  218.                 return childPhrases;
  219.             }
  220.  
  221.             var res1 = ResolveSamePhrasePairs(childPhrases);
  222.             var res2 = ResolveSiblings(res1);
  223.  
  224.             var res = res2;
  225.             bool hasChanges;
  226.             do
  227.             {
  228.                 res = ResolveOverlaid(res, out hasChanges);
  229.             } while (hasChanges);
  230.  
  231.             done = false;
  232.             return res;
  233.         }
  234.  
  235.         private List<WordsPhrase> ResolveSamePhrasePairs(List<WordsPhrase> phrases)
  236.         {
  237.             List<WordsPhrase> result = new List<WordsPhrase>();
  238.             for (int i = 0; i < phrases.Count;)
  239.             {
  240.                 if (i == phrases.Count - 1)
  241.                 {
  242.                     result.Add(phrases[i]);
  243.                     i += 1;
  244.                     continue;
  245.                 }
  246.  
  247.                 var phrase1 = phrases[i];
  248.                 var phrase2 = phrases[i + 1];
  249.  
  250.                 if (phrase1.Phrase != phrase2.Phrase)
  251.                 {
  252.                     result.Add(phrases[i]);
  253.                     i += 1;
  254.                     continue;
  255.                 }
  256.  
  257.                 ResolvePair(result, phrase1, phrase2);
  258.  
  259.                 i += 2;
  260.             }
  261.             RemoveFullDuplicates(result);
  262.             return result;
  263.         }
  264.  
  265.         private List<WordsPhrase> ResolveSiblings(List<WordsPhrase> phrases)
  266.         {
  267.             List<WordsPhrase> result = new List<WordsPhrase>();
  268.             for (int i = 0; i < phrases.Count;)
  269.             {
  270.                 if (i == phrases.Count - 1)
  271.                 {
  272.                     result.Add(phrases[i]);
  273.                     i += 1;
  274.                     continue;
  275.                 }
  276.  
  277.                 var phrase1 = phrases[i];
  278.                 var phrase2 = phrases[i + 1];
  279.  
  280.                 if (phrase1.Parent == null || phrase1.Parent != phrase2.Parent)
  281.                 {
  282.                     result.Add(phrases[i]);
  283.                     i += 1;
  284.                     continue;
  285.                 }
  286.  
  287.                 ResolvePair(result, phrase1, phrase2);
  288.  
  289.                 i += 2;
  290.             }
  291.             RemoveFullDuplicates(result);
  292.             return result;
  293.         }
  294.  
  295.         private List<WordsPhrase> ResolveOverlaid(List<WordsPhrase> phrases, out bool hasChanges)
  296.         {
  297.             hasChanges = false;
  298.             List<WordsPhrase> result = new List<WordsPhrase>();
  299.             for (int i = 0; i < phrases.Count;)
  300.             {
  301.                 if (i == phrases.Count - 1)
  302.                 {
  303.                     result.Add(phrases[i]);
  304.                     i += 1;
  305.                     continue;
  306.                 }
  307.  
  308.                 var phrase1 = phrases[i];
  309.                 var phrase2 = phrases[i + 1];
  310.  
  311.                 if (!IsTokensOverlaids(phrase1.Tokens, phrase2.Tokens))
  312.                 {
  313.                     result.Add(phrase1);
  314.                     i += 1;
  315.                     continue;
  316.                 }
  317.  
  318.                 hasChanges = true;
  319.                 ResolvePair(result, phrase1, phrase2);
  320.  
  321.                 if (result.Contains(null))
  322.                 {
  323.                 }
  324.  
  325.                 i += 2;
  326.             }
  327.             RemoveFullDuplicates(result);
  328.             return result;
  329.         }
  330.  
  331.         private const double threshold = 0.6;
  332.  
  333.         private static void ResolvePair(List<WordsPhrase> result, WordsPhrase phrase1, WordsPhrase phrase2)
  334.         {
  335.             var status1 = phrase1.Status;
  336.             var status2 = phrase2.Status;
  337.  
  338.             if (phrase1.Status == phrase2.Status)
  339.             {
  340.                 if (status1 == CompareStatus.Worse)
  341.                 {
  342.                     result.Add(phrase1.Parent);
  343.                     result.Add(phrase2.Parent);
  344.                 }
  345.                 else if (status1 == CompareStatus.Questionable)
  346.                 {
  347.                     // временно!
  348.                     // нужно учитывать веса у родителей
  349.                     double maxWeight = Math.Max(phrase1.Weight, phrase2.Weight);
  350.  
  351.                     if (maxWeight > threshold)
  352.                     {
  353.                         var tmpPhrase = GetWhere(phrase1, phrase2, p => p.Weight == maxWeight);
  354.                         result.Add(tmpPhrase);
  355.                     }
  356.                     else
  357.                     {
  358.                         result.Add(phrase1.Parent);
  359.                         result.Add(phrase2.Parent);
  360.                     }
  361.                 }
  362.                 else if (status1 == CompareStatus.Better)
  363.                 {
  364.                     // ???временно! кладем просто первй
  365.                     // ???но возможно потребуется откат до родителя для вторго, нужно перепроверить
  366.  
  367.                     // кладем с большим весом
  368.                     var tmpPhrase = phrase1.Weight >= phrase2.Weight ? phrase1 : phrase2;
  369.                     result.Add(tmpPhrase);
  370.                 }
  371.                 else // None
  372.                 {
  373.                     // wut??? не должно происходить ??
  374.                     result.Add(phrase1);
  375.                     result.Add(phrase2);
  376.                 }
  377.             }
  378.             else
  379.             {
  380.                 if (IsOneEquals(status1, status2, CompareStatus.Questionable))
  381.                 {
  382.                     if (IsOneEquals(status1, status2, CompareStatus.Better))
  383.                     {
  384.                         var betterPhrase = GetWhere(phrase1, phrase2, s => s.Status == CompareStatus.Better);
  385.                         result.Add(betterPhrase);
  386.                     }
  387.                     else if (IsOneEquals(status1, status2, CompareStatus.Worse))
  388.                     {
  389.                         result.Add(phrase1.Parent ?? phrase1);
  390.                         result.Add(phrase2.Parent ?? phrase2);
  391.                     }
  392.                     else
  393.                     {
  394.                         var questionablePhrase = GetWhere(phrase1, phrase2, s => s.Status == CompareStatus.Questionable);
  395.                         if (questionablePhrase.Weight > threshold)
  396.                         {
  397.                             result.Add(questionablePhrase);
  398.                         }
  399.                         else
  400.                         {
  401.                             result.Add(phrase1.Parent ?? phrase1);
  402.                             result.Add(phrase2.Parent ?? phrase2);
  403.                         }
  404.                         // wut???
  405.                         // не должно происходить!
  406.                     }
  407.                 }
  408.                 else if (IsOneEquals(status1, status2, CompareStatus.Better))
  409.                 {
  410.                     var betterPhrase = GetWhere(phrase1, phrase2, s => s.Status == CompareStatus.Better);
  411.                     result.Add(betterPhrase);
  412.                 }
  413.                 else
  414.                 {
  415.                     result.Add(phrase1.Parent ?? phrase1);
  416.                     result.Add(phrase2.Parent ?? phrase2);
  417.                 }
  418.             }
  419.         }
  420.  
  421.         private void RemoveFullDuplicates(List<WordsPhrase> phrases)
  422.         {
  423.             for (int i = 0; i < phrases.Count - 1; i++)
  424.             {
  425.                 var phrase1 = phrases[i];
  426.                 var phrase2 = phrases[i + 1];
  427.                 if (phrase1 == phrase2)
  428.                 {
  429.                     phrases.RemoveAt(i + 1);
  430.                 }
  431.             }
  432.         }
  433.  
  434.         private bool IsTokensOverlaids(List<Token> tokens1, List<Token> tokens2)
  435.         {
  436.             for (int i = 0; i < tokens1.Count; i++)
  437.             {
  438.                 for (int j = 0; j < tokens2.Count; j++)
  439.                 {
  440.                     if (tokens1[i] == tokens2[j])
  441.                         return true;
  442.                 }
  443.             }
  444.             return false;
  445.         }
  446.  
  447.         private enum CompareStatus
  448.         {
  449.             None,
  450.             Better,
  451.             Worse,
  452.             Questionable
  453.         }
  454.  
  455.         private static T GetWhere<T>(T obj1, T obj2, Predicate<T> predicate)
  456.             where T : class
  457.         {
  458.             if (predicate(obj1))
  459.                 return obj1;
  460.             if (predicate(obj2))
  461.                 return obj2;
  462.             return null;
  463.         }
  464.  
  465.         private static bool IsOneEquals(CompareStatus status1, CompareStatus status2, CompareStatus toCompare)
  466.         {
  467.             return status1 == toCompare || status2 == toCompare;
  468.         }
  469.  
  470.         const double epsilon = 0;//-0.002;
  471.  
  472.         private CompareStatus ComparePhrases(WordsPhrase newPhrase, WordsPhrase oldPhrase)
  473.         {
  474.             string newName = newPhrase.Label;
  475.             string oldName = oldPhrase.Label;
  476.             if (newName != Other && oldName != Other)
  477.             {
  478.                 if (newName == oldName)
  479.                 {
  480.                     double newConf = newPhrase.Weight;
  481.                     double oldConf = oldPhrase.Weight;
  482.  
  483.                     double delta = newConf - oldConf;
  484.  
  485.                     return delta > epsilon ? CompareStatus.Better : CompareStatus.Worse; // однозначно лучше, если уверенность больше
  486.                 }
  487.                 else
  488.                     return CompareStatus.Questionable;    // questionable
  489.             }
  490.  
  491.             if (newName == Other && oldName == Other)
  492.             {
  493.                 return CompareStatus.Worse;   // оба Other - нет смысла обрабатывать
  494.             }
  495.  
  496.             return CompareStatus.Questionable;    // если новый не Other то лучше
  497.         }
  498.  
  499.         private WordsPhrase ConcatenatePhrases(WordsPhrase phrase1, WordsPhrase phrase2, List<Token> sourceTokens, ClassifierEngineData engineData)
  500.         {
  501.             List<Token> sumTokens = phrase1.Tokens.Concat(phrase2.Tokens).ToList();
  502.             return TokensToPhrase(sumTokens, sourceTokens, engineData);
  503.         }
  504.  
  505.         private List<WordsPhrase> GenerateInitialPhrases(List<Token> tokens, List<Token> sourceTokens, ClassifierEngineData engineData)
  506.         {
  507.             List<WordsPhrase> wordsPhrases = new List<WordsPhrase>();
  508.  
  509.             List<int> continiousTokensIndexes = DetectContiniousTokens(tokens, sourceTokens);
  510.             var continiousTokensRanges = CollectContiniousRanges(continiousTokensIndexes).ToDictionary(r => r.Start);
  511.  
  512.             for (int i = 0; i < tokens.Count;)
  513.             {
  514.                 int start = i;
  515.                 int len = 1;
  516.                 if (continiousTokensRanges.TryGetValue(start, out var range))
  517.                 {
  518.                     len = range.Length;
  519.                 }
  520.  
  521.                 List<Token> phraseTokens = tokens.Skip(start).Take(len).ToList();
  522.                 WordsPhrase phrase = TokensToPhrase(phraseTokens, sourceTokens, engineData);
  523.                 //phrase.Status = CompareStatus.Better;
  524.                 wordsPhrases.Add(phrase);
  525.                 i += len;
  526.             }
  527.             return wordsPhrases;
  528.         }
  529.  
  530.         /// <summary>
  531.         /// Собирает все токены из <paramref name="phraseTokens"/> вместе с пропущенными (игнорируемыми) используя все токены предложения <paramref name="sourceTokens"/>.
  532.         /// </summary>
  533.         /// <param name="phraseTokens"></param>
  534.         /// <param name="sourceTokens"></param>
  535.         /// <returns></returns>
  536.         private static List<Token> GetAllTokensWithSeparators(List<Token> phraseTokens, List<Token> sourceTokens)
  537.         {
  538.             if (phraseTokens.Count == 1)
  539.                 return phraseTokens;
  540.  
  541.             int firstTokenIdx = sourceTokens.IndexOf(phraseTokens[0]);
  542.             int lastTokenIdx = sourceTokens.LastIndexOf(phraseTokens[phraseTokens.Count - 1]);
  543.  
  544.             List<Token> result = sourceTokens.Skip(firstTokenIdx).Take(lastTokenIdx - firstTokenIdx + 1).ToList();
  545.  
  546.             return result;
  547.         }
  548.  
  549.         /// <summary>
  550.         /// Возвращает список из наиболее вероятных полей для данного слова.
  551.         /// </summary>
  552.         /// <param name="wordVec"></param>
  553.         /// <param name="topN"></param>
  554.         /// <returns></returns>
  555.         private List<Tuple<string, double>> GetTopFields(string[] allLabels, float[] wordVec, int topN)
  556.         {
  557.             List<Tuple<string, double>> result = new List<Tuple<string, double>>();
  558.             for (int i = 0; i < wordVec.Length; i++)
  559.             {
  560.                 if (wordVec[i] > 0.0)
  561.                     result.Add(new Tuple<string, double>(allLabels[i], wordVec[i]));
  562.             }
  563.             return result.OrderByDescending(w => w.Item2).Take(topN).ToList();
  564.         }
  565.  
  566.         public static double GetDegreeOfConfidence(float[] vals)
  567.         {
  568.             double max = vals.Max();
  569.             var avg = MathHelper.AvgStdDev(vals, out double stdDev);
  570.             double thr = stdDev * 0.1;
  571.  
  572.             double sum = 0;
  573.             int countNonZero = 0;
  574.             for (int i = 0; i < vals.Length; i++)
  575.             {
  576.                 if (vals[i] > thr)
  577.                 {
  578.                     countNonZero++;
  579.                     double normVal = vals[i] / max;
  580.                     sum += normVal * normVal;
  581.                 }
  582.             }
  583.             if (countNonZero == 1)
  584.                 return 1;
  585.             if (countNonZero == 0)
  586.                 return 0;
  587.             if (sum == countNonZero)
  588.                 return max;
  589.             double res = Math.Sqrt(sum / countNonZero);
  590.             return (1 - res) / (1 - Math.Sqrt(1.0 / countNonZero));
  591.         }
  592.  
  593.         private double CalcResultCoef(WordsPhrase t)
  594.         {
  595.             return 0.2 * t.Weight + 0.8 * t.Weight;// + 0.1 / maxPhraseLen * t.Tokens.Count;
  596.         }
  597.  
  598.         private List<IndexRange> CollectContiniousRanges(List<int> indexes)
  599.         {
  600.             List<IndexRange> result = new List<IndexRange>();
  601.             if (indexes.Count == 0)
  602.                 return result;
  603.  
  604.             int startIdx = indexes[0];
  605.             int len = 1;
  606.             for (int i = 1; i < indexes.Count; i++)
  607.             {
  608.                 if (indexes[i] - len == startIdx)
  609.                     len++;
  610.                 else
  611.                 {
  612.                     result.Add(new IndexRange(startIdx, len + 1));
  613.                     startIdx = indexes[i];
  614.                     len = 1;
  615.                 }
  616.             }
  617.             result.Add(new IndexRange(startIdx, len + 1));
  618.             return result;
  619.         }
  620.  
  621.         HashSet<string> prepositions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "with", "without", "w/", "w/o" };
  622.  
  623.         private List<int> DetectContiniousTokens(List<Token> tokens, List<Token> sourceTokens)
  624.         {
  625.             List<int> result = new List<int>();
  626.             if (tokens.Count <= 1)
  627.                 return result;
  628.  
  629.             List<Token> twoTokens = new List<Token>();
  630.             for (int i = 0; i < tokens.Count - 1; i++)
  631.             {
  632.                 if (prepositions.Contains(tokens[i].Word))
  633.                 {
  634.                     result.Add(i);
  635.                     continue;
  636.                 }
  637.  
  638.                 twoTokens.Add(tokens[i]);
  639.                 twoTokens.Add(tokens[i + 1]);
  640.  
  641.                 List<Token> allPhraseTokens = GetAllTokensWithSeparators(twoTokens, sourceTokens);
  642.                 string sumWord = TagTokenHelper.RecollectTagsWord(allPhraseTokens);
  643.                 bool containsWhitespace = IsContainsWhitespace(sumWord);
  644.                 if (!containsWhitespace)
  645.                     result.Add(i);
  646.                 twoTokens.Clear();
  647.             }
  648.             return result;
  649.         }
  650.  
  651.         /// <summary>
  652.         /// Проверяет содержатся ли пробелы в тексте.
  653.         /// </summary>
  654.         /// <param name="sumWord"></param>
  655.         /// <returns></returns>
  656.         private bool IsContainsWhitespace(string sumWord)
  657.         {
  658.             foreach (char ch in sumWord)
  659.             {
  660.                 if (char.IsWhiteSpace(ch))
  661.                     return true;
  662.             }
  663.             return false;
  664.         }
  665.  
  666.         private bool CheckContiniousTokens(List<IndexRange> continiousTokensRanges, IndexRange range)
  667.         {
  668.             bool overlapse = continiousTokensRanges.Any(t => IsOverlapse(t, range));
  669.             if (overlapse)
  670.                 return false;
  671.  
  672.             bool b1 = !continiousTokensRanges.Any(t => IsFirstInsideOfSecond(range, t));
  673.             bool b2 = continiousTokensRanges.Any(t => IsFirstInsideOfSecond(t, range));
  674.             return b1 || b2;
  675.         }
  676.  
  677.         private bool IsOverlapse(IndexRange r1, IndexRange r2)
  678.         {
  679.             return IsIndexInside(r1, r2.Start) ^ IsIndexInside(r1, r2.Start + r2.Length);
  680.         }
  681.  
  682.         private bool IsFirstInsideOfSecond(IndexRange first, IndexRange second)
  683.         {
  684.             return first.Start >= second.Start && first.Start + first.Length <= second.Start + second.Length;
  685.         }
  686.  
  687.         private bool IsIndexInside(IndexRange range, int idx)
  688.         {
  689.             return idx > range.Start && idx < range.Start + range.Length;
  690.         }
  691.  
  692.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement