using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExtensionMethods;
namespace CryptanalysisCore
{
public class UniqueWords
{
///
/// Seznam všech unikátních slov ze slovníku
/// roztříděných do tříd ekvivalence.
///
private Dictionary> uniqueWords;
///
/// Unikátní slova nalezená v předaném textu. Viz metoda Find.
///
private Dictionary uniquePairs;
///
/// Vyfiltrované páry
///
private Dictionary bestPairs;
public UniqueWords(string[] uniqueWords)
{
this.uniqueWords = EquivalenceClass(uniqueWords);
uniquePairs = null;
}
///
/// Vrátí všechna slova z words, která jsou unikátní
/// (Tj. která mají vzor v uniqueWords)
///
///
///
public Dictionary Find(string[] words)
{
int index;
Dictionary unique = new Dictionary();
foreach (string word in words)
{
index = GetEqIndex(word);
if (uniqueWords.ContainsKey(index))
{
string uniqueWord = GetPattern(word, uniqueWords[index]);
if (uniqueWord != null)
{
unique[word] = uniqueWord;
}
}
}
uniquePairs = unique;
return uniquePairs;
}
///
/// Vrátí nejpravděpodobnější substituce písmen založené
/// na unikátních slovech.
///
///
///
public Dictionary GetLettersSubst(string[] words)
{
Find(words);
var bestPairs = Filter();
return bestPairs != null ? TextAnalysis.GetLetterSubst(bestPairs) : null;
}
///
/// Projde nalezené unikátní dvojice a pokusí se z
/// nich vyfiltrovat ty, které tam nesedí.
///
///
public Dictionary Filter()
{
WordsFilter uniqueFilter = new WordsFilter(uniquePairs);
bestPairs = uniqueFilter.Filter(ArePairsMatch);
return uniqueFilter.Checked ? bestPairs : null;
}
///
/// Odpovídají si předané dvojice unikátních slov?
///
///
///
///
private bool ArePairsMatch(KeyValuePair pair1, KeyValuePair pair2)
{
var subst1 = TextAnalysis.GetLettersSubst(pair1);
var subst2 = TextAnalysis.GetLettersSubst(pair2);
return TextAnalysis.AreSubstMatch(subst1, subst2);
}
///
/// Vrátí to slovo ze seznamu, které má stejný vzor jako předané slovo.
///
///
///
///
private string GetPattern(string word, List uniqueWords)
{
foreach (string uniqueWord in uniqueWords)
if (SamePattern(word, uniqueWord))
return uniqueWord;
return null;
}
///
/// Zjistí, zda předaná slova mají stejný vzor.
///
///
///
/// true v případě, že slova mají stejný vzor, false jinak
public static bool SamePattern(string word1, string word2)
{
if (word1.Length != word2.Length)
return false;
var checkedChars = new List();
var sameChars = new List>();
List temp;
char currentChar;
// Nalezneme stejná písmena v prvním slově
for (int i = 0; i < word1.Length; i++)
{
currentChar = word1[i];
if (checkedChars.Find(currentChar))
continue;
checkedChars.Add(currentChar);
temp = new List();
temp.Add(i);
for (int j = i + 1; j < word1.Length; j++)
if (word1[j] == currentChar)
temp.Add(j);
sameChars.Add(temp);
}
// Zjistíme, zda druhé slovo odpovídá vzoru
List findedChars = new List();
char findedChar;
foreach (var same in sameChars)
{
findedChar = word2[same[0]];
if (findedChars.Find(findedChar))
return false;
findedChars.Add(findedChar);
if (same.Count > 1)
foreach (int index in same)
{
if (word2[index] != word2[same[0]])
return false;
}
}
return true;
}
///
/// Zjistí, zda je dané slovo unikátní vzhledem k předaným slovům
///
///
///
///
private bool IsWordUnique(string testWord, string[] words)
{
foreach (string word in words)
{
if (SamePattern(word, testWord) && word != testWord)
return false;
}
return true;
}
///
/// Od začátku slova počítá písmena, dokud nenarazí na jedno písmeno dvakrát
///
///
///
private int CountDiffFirstLetters(string word)
{
List finded = new List();
for (int i = 0; i < word.Length; i++)
if (finded.Find(word[i]))
return i;
else
finded.Add(word[i]);
return word.Length;
}
private int CountDiffZiggzaggLetters(string word)
{
List finded = new List();
for (int i = 0; i < word.Length; i += 2)
if (finded.Find(word[i]))
return finded.Count();
else
finded.Add(word[i]);
return finded.Count();
}
private int CountDiffLastLetters(string word)
{
return CountDiffFirstLetters(word.Reverse());
}
///
/// Roztřídí předaná slova do tříd ekvivalence,
/// aby se nemuselo každé slovo prohledávat s každým jiným.
///
///
///
public Dictionary> EquivalenceClass(string[] words)
{
Dictionary> eqTexts = new Dictionary>();
for (int i = 0; i < 100; i++)
eqTexts[i] = new List();
foreach (string text in words)
eqTexts[text.Length].Add(text);
var wordLengthEq = eqTexts.Where(x => x.Key <= 30 && x.Key > 7 && x.Value.Count > 0).Select(x => x.Value.Distinct().ToArray()).ToArray();
var difffirstletter = DifferentPosLetters(wordLengthEq);
return difffirstletter;
}
///
/// Rozdělí slova do tříd ekvivalence na základě počtu různých písmen
/// od začátku, od konce a ob dva.
///
///
///
private Dictionary> DifferentPosLetters(string[][] texts)
{
Dictionary> eqTexts = new Dictionary>();
int index;
foreach (string[] text in texts)
{
foreach (string word in text)
{
index = GetEqIndex(word);
if (eqTexts.ContainsKey(index))
eqTexts[index].Add(word);
else
eqTexts[index] = new List() { word };
}
}
return eqTexts;
}
///
/// Spočítá index pro použití v třídách ekvivalence
///
///
///
private int GetEqIndex(string word)
{
int firstDiff, lastDiff, ziggzaggDiff, index;
firstDiff = CountDiffFirstLetters(word);
lastDiff = CountDiffLastLetters(word);
ziggzaggDiff = CountDiffZiggzaggLetters(word);
index = firstDiff + 30 * lastDiff + 900 * ziggzaggDiff + 900 * 30 * word.Length;
return index;
}
///
/// Vrátí seznam unikátních slov, použití ve statistice
///
///
///
public List GetUniqueWords()
{
// upgrade test
//var textsArr = texts.Where(x => x.Value.Count < 3000).Select(x => x.Value.ToArray()).ToArray();
var textsArr = uniqueWords.Where(x => x.Value.Count < 3000).Select(x => x.Value.ToArray()).ToArray();
List uniqueWords2 = new List();
int counter = 1;
foreach (string[] words in textsArr)
{
string[] unique = GetUniqueWordsFromArray(words);
if (unique.Length > 0)
uniqueWords2.Add(unique);
counter++;
}
return uniqueWords2;
}
///
/// Vrátí seznam unikátních slov v daném poli
///
///
///
private string[] GetUniqueWordsFromArray(string[] words)
{
List uniqueWords = new List();
foreach (string word in words)
{
if (IsWordUnique(word, words))
uniqueWords.Add(word);
}
return uniqueWords.ToArray();
}
}
}