using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Lab4.ChainedWords
{
static class TaskUtils
{
///
/// Return anything that matches a word in given text, depending on punctuation
///
/// Target text
/// Target punctuation
/// Word matches
private static MatchCollection MatchByWords(string text, string punctuation)
{
string pattern = string.Format(@"[^{0}\n]+", Regex.Escape(punctuation));
return Regex.Matches(text, pattern, RegexOptions.IgnoreCase);
}
///
/// Return anything that matches a positive integer in text
///
/// Target text
/// Integer matches
private static MatchCollection MatchByIntegers(string text)
{
return Regex.Matches(text, @"\d+");
}
///
/// Find all chains of words in given text. A chain is a sequence of words where every words
/// last letter matches the next words first letter. And split the text into words using punctuation
///
/// Target text
/// Target punctuation
/// A list of chains with line number where it was found
public static List> FindChains(string text, string punctuation)
{
List> chains = new List>();
bool startedChain = false;
int chainStart = 0;
MatchCollection matches = MatchByWords(text, punctuation);
for (int i = 1; i < matches.Count; i++)
{
Match prevMatch = matches[i-1];
Match match = matches[i];
bool matchesCriteria = prevMatch.Value.ToLowerInvariant().Last() == match.Value.ToLowerInvariant().First();
if (matchesCriteria && !startedChain)
{
startedChain = true;
chainStart = prevMatch.Index;
}
else if (!matchesCriteria && startedChain)
{
startedChain = false;
int line = text.Substring(0, chainStart).Count(c => c == '\n')+1;
string chain = text.Substring(chainStart, match.Index-chainStart).TrimEnd('\n');
chains.Add(new Tuple(line, chain));
}
}
// Ensure that last chain gets added to list
if (startedChain)
{
int line = text.Substring(0, chainStart).Count(c => c == '\n')+1;
string chain = text.Substring(chainStart).TrimEnd('\n');
chains.Add(new Tuple(line, chain));
}
return chains;
}
///
/// Find all positive integers in given text
///
/// Target text
/// List of positive integers
public static List FindIntegers(string text)
{
List integers = new List();
MatchCollection matches = MatchByIntegers(text);
foreach (Match match in matches)
{
integers.Add(int.Parse(match.Value));
}
return integers;
}
///
/// Finds the longest chain in the given text, while using given punctuation to determine words.
///
/// Target text
/// Target punctuation
///
public static Tuple FindLongestChain(string text, string punctuation)
{
List> chains = FindChains(text, punctuation);
if (chains.Count == 0)
{
return null;
}
Tuple longestChain = chains[0];
foreach (var pair in chains)
{
if (pair.Item2.Length > longestChain.Item2.Length)
{
longestChain = pair;
}
}
return longestChain;
}
///
/// Ouput to file:
/// * longest chain and where it was found
/// * sum of all positive integers
///
/// Input file
/// Output file
/// Target punctuation
public static void ProcessChains(string inputFile, string outputFile, string punctuation)
{
string text = File.ReadAllText(inputFile, Encoding.UTF8);
Tuple longestChain = FindLongestChain(text, punctuation);
List integers = FindIntegers(text);
using (StreamWriter writer = new StreamWriter(outputFile))
{
if (longestChain != null)
{
writer.WriteLine("Ilgiausia žodžių grandinė {0} eilutėje: {1}", longestChain.Item1, longestChain.Item2);
}
else
{
writer.WriteLine("Nėra žodžių grandinių.");
}
writer.WriteLine("Yra {0} žodžiai sudaryti iš skaitmenų. Jų suma: {1}", integers.Count, integers.Sum());
}
}
private static string AlignWordsByColumns(List> words, string punctuation)
{
StringBuilder aligned = new StringBuilder();
Dictionary columns = new Dictionary();
foreach (List row in words)
{
int column = 0;
foreach (string word in row)
{
if (!columns.ContainsKey(column))
{
columns.Add(column, 0);
}
columns[column] = Math.Max(columns[column], word.Length);
column++;
}
}
foreach (List row in words)
{
int column = 0;
for (int i = 0; i < row.Count; i++)
{
string word = row[i];
aligned.Append(word);
if (i < row.Count - 1)
{
aligned.Append(new string(' ', columns[column] - word.Length));
}
column++;
}
aligned.Append("\n");
}
return aligned.ToString();
}
///
/// Align every word in a line by columns
///
/// Input file
/// Output file
/// Target punctuation
public static void ProcessAligned(string inputFile, string outputFile, string punctuation)
{
string pattern = string.Format(@"[^{0}]+[{0}]*", Regex.Escape(punctuation));
string text = File.ReadAllText(inputFile, Encoding.UTF8);
List> words = new List>();
foreach (string line in InOut.ReadByLines(inputFile))
{
List row = new List();
words.Add(row);
foreach (Match match in Regex.Matches(line, pattern))
{
row.Add(match.Value.TrimEnd('\n'));
}
}
File.WriteAllText(outputFile, AlignWordsByColumns(words, punctuation));
}
///
/// Align every line by columns and print words vertically
///
/// Input file
/// Output file
/// Punctuation
public static void ProccessVericallyAligned(string inputFile, string outputFile, string punctuation)
{
string pattern = string.Format(@"[^{0}]+[{0}]*", Regex.Escape(punctuation));
string text = File.ReadAllText(inputFile, Encoding.UTF8);
List> words = new List>();
foreach (string line in InOut.ReadByLines(inputFile))
{
int column = 0;
int row = 0;
foreach (Match match in Regex.Matches(line, pattern))
{
if (words.Count <= row)
{
words.Add(new List());
}
words[row].Add(match.Value.TrimEnd('\n'));
row++;
}
column++;
}
File.WriteAllText(outputFile, AlignWordsByColumns(words, punctuation));
}
}
}