using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ExtensionMethods;
namespace CryptanalysisCore
{
public static class TextAnalysis
{
///
/// Vrátí dvojice ve tvaru znak:počet výskytů na začátku slova
///
/// seznam slov
///
public static Dictionary StartLetters(string[] words)
{
return SomeLetters(words, word => word[0]);
}
///
/// Vrátí dvojice ve tvaru znak:počet výskytů na konci slova
///
/// seznam slov
///
public static Dictionary EndLetters(string[] words)
{
return SomeLetters(words, word => word[word.Length - 1]);
}
///
/// Najde ve slově písmeno, které vrátí předaná selektivní funkce
/// a spočítá, kolikrát se toto písmeno vyskytuje ve všech slov.
/// Vrátí jako dvojice písmeno:počet výskytů
///
/// seznam slov
/// Selektivní funkce vracející písmeno ze slova
///
public static Dictionary SomeLetters(string[] words, Func selectLetter)
{
var letters = new Dictionary();
Analyse.DoAlphabet(l => letters[l] = 0);
words.ForEach(word => letters[selectLetter(word)]++);
int count = 0;
letters.ForEach(x => count += x.Value);
return letters.OrderByDescending(x => x.Value)
.ToDictionary(x => x.Key.ToString(), x => ((double)x.Value / (double)count) * 100);
}
///
/// Vrátí relativní výskyt jednotlivých ngramů v textu.
///
/// Text, ve kterém se budou hledat ngramy
/// Délka ngramu. 1+
///
public static Dictionary GetOccurrence(string text, int length)
{
Dictionary occurrence = new Dictionary();
string ngram;
for (int i = 0; i < text.Length - length + 1; i++)
{
ngram = text.Substring(i, length);
if (occurrence.ContainsKey(ngram))
occurrence[ngram]++;
else
occurrence[ngram] = 1;
}
double multiply = (double)text.Length / 100;
Dictionary relativeOccurrence = new Dictionary();
foreach (KeyValuePair occPair in occurrence)
relativeOccurrence[occPair.Key] = (double)occPair.Value / multiply;
if (length == 1)
{
Analyse.DoAlphabet(x =>
{
if (!relativeOccurrence.ContainsKey(x.ToString()))
relativeOccurrence[x.ToString()] = 0;
});
}
return relativeOccurrence.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, y => y.Value);
}
///
/// Zjistí, zda je dané písmeno z anglické abecedy [a-zA-Z]
///
/// Jakýkoliv znak
/// true: znak anglické abecedy, false: jinak
public static bool IsEnglishLetter(char character)
{
return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z');
}
///
/// Vrátí řetězec, který obsahuje pouze písmena a mezery,
/// přičemž nedovolí mít dvě mezery za sebou.
///
///
///
public static string GetLetters(string s)
{
StringBuilder sb = new StringBuilder();
foreach (char c in s)
{
if (IsEnglishLetter(c))
sb.Append(c);
else
{
if (c == ' ')
{
if (sb.Length == 0 || sb[sb.Length - 1] != ' ')
sb.Append(' ');
}
}
}
return sb.ToString();
}
///
/// Vrátí průměrný počet výskytů písmen před a po nějakém písmenu.
///
///
///
public static NearbyLetters NearbyLetters(string[] words)
{
return NearbyLetters(words, 150);
}
///
/// Vrátí průměrný počet výskytů písmen před a po nějakém písmenu.
///
///
/// Kolik slov mají mít jednotlivé části,
/// ve kterých se to bude počítat.
///
public static NearbyLetters NearbyLetters(string[] words, int partSize)
{
Dictionary nextLetters = new Dictionary();
Dictionary prevLetters = new Dictionary();
List foundNextLetters = new List();
List foundPrevLetters = new List();
char letter;
for (int j = (int)'a'; j <= (int)'z'; j++)
{
nextLetters[(char)j] = 0;
prevLetters[(char)j] = 0;
}
for (int part = 0; part <= words.Length / partSize; part++)
{
var takenarr = words.Take(part * partSize, partSize);
for (int j = (int)'a'; j <= (int)'z'; j++)
{
letter = (char)j;
foundNextLetters.Clear();
foundPrevLetters.Clear();
foreach (string word in takenarr)
{
for (int i = 0; i < word.Length; i++)
{
if (word[i] == letter)
{
if ((i < word.Length - 1) && !foundNextLetters.Find(word[i + 1]))
foundNextLetters.Add(word[i + 1]);
if ((i > 0) && !foundPrevLetters.Find(word[i - 1]))
foundPrevLetters.Add(word[i - 1]);
}
}
}
nextLetters[letter] += foundNextLetters.Count();
prevLetters[letter] += foundPrevLetters.Count();
}
}
int count = 0;
nextLetters.ForEach(x => count += x.Value);
double multiply = (double)count / 100;
var resNext = nextLetters.ToDictionary(x => x.Key.ToString(), x => (double)x.Value / multiply);
count = 0;
nextLetters.ForEach(x => count += x.Value);
multiply = (double)count / 100;
var resPrev = prevLetters.ToDictionary(x => x.Key.ToString(), x => (double)x.Value / multiply);
return new NearbyLetters(resPrev, resNext);
}
///
/// Zjišťuje, jestli je daný otevřený text validní vstup do šifrovací funkce
///
/// Otevřený text
/// true - text je v pořádku; false - v textu je nějaká chyba
public static bool IsOpentextValid(string opentext)
{
return Regex.IsMatch(opentext, @"^[a-z ]*$");
}
///
/// Zjišťuje, jestli je daný šifrový text validní vstup do dešifrovací funkce
///
/// Šifrový text
/// true - text je v pořádku; false - v textu je nějaká chyba
public static bool IsCiphertextValid(string ciphertext)
{
return Regex.IsMatch(ciphertext, @"^[A-Z ]*$");
}
///
/// Převede obyčejný string na pole slov.
///
/// Libovolný text
/// Pole slov.
public static string[] ToWords(string text)
{
return Analyse.NormalizeText(text, Analyse.TextTypes.WithSpacesLower).Split(' ').Where(x => x.Length > 0).ToArray();
}
///
/// Najde ty bigramy, pro které můžeme v seznamu bigramů najít i jejich převrácený tvar
///
/// Pole bigramů
///
public static List GetSymetricBigrams(string[] bigrams)
{
List symBigrams = new List();
foreach (string bigram in bigrams)
{
if ((Array.Find(bigrams, x => bigram[0] == x[1] && bigram[1] == x[0]) != null) &&
symBigrams.Find(pair => pair[0] == bigram || pair[1] == bigram) == null)
symBigrams.Add(new string[] { bigram, bigram.ToCharArray().Reverse().ToList().Implode("") });
}
return symBigrams;
}
///
/// Vrátí slovník reprezentující substituce mezi slovy
///
///
///
public static Dictionary GetLettersSubst(Dictionary wordPairs)
{
Dictionary substitutions = new Dictionary();
foreach (var pair in wordPairs)
{
for (int i = 0; i < pair.Key.Length; i++)
{
substitutions[pair.Key[i]] = pair.Value[i];
}
}
return substitutions;
}
///
/// Vrátí slovník reprezentující substituce mezi slovy
/// sloučený z již existujícími substitucemi
///
///
///
///
public static Dictionary GetLettersSubst(Dictionary wordPairs, Dictionary substitutions)
{
Dictionary subsPairs = GetLettersSubst(wordPairs);
substitutions.ForEach(pair => subsPairs[pair.Key] = pair.Value);
return subsPairs;
}
///
/// Zjistí, zda dané dva slovníky představují stejný vzor substitucí.
/// Kontroluje oba směry. (TODO: Je to vůbec nutné?)
///
///
///
///
public static bool AreSubstMatch(Dictionary subst1, Dictionary subst2)
{
bool res = AreSubstsMatchHelp(subst1, subst2);
if (res)
return AreSubstsMatchHelp(subst2, subst1);
else
return false;
}
///
/// Zjistí, zda dané dva slovníky představují stejný vzor substitucí
///
///
///
///
private static bool AreSubstsMatchHelp(Dictionary subst1, Dictionary subst2)
{
foreach (var pair in subst1)
{
if (subst2.ContainsKey(pair.Key) && pair.Value != subst2[pair.Key])
return false;
}
return true;
}
///
/// Vrátí slovník reprezentující substituce ve slovech
///
///
///
public static Dictionary GetLettersSubst(KeyValuePair pair)
{
Dictionary subst = new Dictionary();
for (int i = 0; i < pair.Key.Length; i++)
subst[pair.Key[i]] = pair.Value[i];
return subst;
}
///
/// Vrátí slovník reprezentující substituce ve slovech
///
///
///
public static Dictionary GetLettersSubst(string word1, string word2)
{
Dictionary subst = new Dictionary();
for (int i = 0; i < word1.Length; i++)
subst[word1[i]] = word2[i];
return subst;
}
public static List PolygonAttack(char[] topTextLetters, char[] topLetters, int complementSize)
{
var variations = Combinatorics.Variations(topTextLetters.ToList(), topLetters.Length);
variations.Reverse();
List matchLetters = new List();
List notMatch = new List();
foreach (var variation in variations)
{
string cut = variation[0].ToString() + variation[1].ToString();
var permutations = Combinatorics.Permutation(variation);
foreach (var permutation in permutations)
{
if (permutation[0] == 'f' && permutation[1] == 'b' && permutation[2] == 'p')
complementSize++;
if (LettersDiff(permutation.ToArray(), topLetters))
{
matchLetters.Add(new string(permutation.ToArray()));
break;
}
}
}
return matchLetters;
}
public static bool LettersDiff(char[] letters, char[] topLetters)
{
int[,] lettersMatrix = GetDiffMatrix(letters);
int[,] topLettersMatrix = GetDiffMatrix(topLetters);
return AreMatrixEqual(lettersMatrix, topLettersMatrix);
}
public static bool AreMatrixEqual(int[,] matrix1, int[,] matrix2)
{
for (int i = 0; i < matrix1.GetLength(0); i++)
{
for (int j = 0; j < matrix1.GetLength(1); j++)
{
if (matrix1[i, j] != matrix2[i, j])
return false;
}
}
return true;
}
public static int[,] GetDiffMatrix(char[] letters)
{
int[,] matrix = new int[letters.Length, letters.Length];
for (int i = 0; i < letters.Length; i++)
{
for (int j = 0; j < letters.Length; j++)
{
matrix[i, j] = Analyse.MinDistance(letters[i], letters[j]);
}
}
return matrix;
}
///
/// Sloučí všechny předané substituce do jedné
///
///
///
public static Dictionary MergeSubstitutions(Dictionary[] substitutions)
{
Dictionary subs = new Dictionary();
foreach (var sub in substitutions)
{
foreach (var mergeSubs in sub)
{
subs[mergeSubs.Key] = mergeSubs.Value;
}
}
return subs;
}
///
/// Vrátí pole zpřeházených textů
///
///
///
///
public static string[] GetShuffledText(string text, int number)
{
string[] shuffle = new string[number];
number.Times(i => shuffle[i] = text.Shuffle());
return shuffle;
}
}
}