Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions TestTask/IReadOnlyStream.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
namespace TestTask
using System;

namespace TestTask
{
/// <summary>
/// Интерфейс для работы с файлом в сильно урезаном виде.
/// Умеет всего 2 вещи: прочитать символ, и перемотать стрим на начало.
/// </summary>
internal interface IReadOnlyStream
internal interface IReadOnlyStream: IDisposable
{
// TODO : Необходимо доработать данный интерфейс для обеспечения гарантированного закрытия файла, по окончанию работы с таковым!
char ReadNextChar();

void ResetPositionToStart();
Expand Down
6 changes: 3 additions & 3 deletions TestTask/LetterStats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
/// <summary>
/// Статистика вхождения буквы/пары букв
/// </summary>
public struct LetterStats
public class LetterStats
{
/// <summary>
/// Буква/Пара букв для учёта статистики.
/// </summary>
public string Letter;
public string Letter { get; set; }

/// <summary>
/// Кол-во вхождений буквы/пары.
/// </summary>
public int Count;
public int Count{get;set;}
}
}
184 changes: 154 additions & 30 deletions TestTask/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace TestTask
{
public class Program
{
private static readonly HashSet<char> _vowels = new HashSet<char>("ЁУЕЫАОЭЯИЮ");

/// <summary>
/// Программа принимает на входе 2 пути до файлов.
Expand All @@ -16,19 +19,44 @@ public class Program
/// Второй параметр - путь до второго файла.</param>
static void Main(string[] args)
{
IReadOnlyStream inputStream1 = GetInputStream(args[0]);
IReadOnlyStream inputStream2 = GetInputStream(args[1]);
if (args == null|| args.Length <2)
{
Console.WriteLine("Нужно указать пути к двум файлам");
Console.ReadKey(true);
return;
}

try
{
using (IReadOnlyStream inputStream1 = GetInputStream(args[0]))
using (IReadOnlyStream inputStream2 = GetInputStream(args[1]))
{
IList<LetterStats> singleLetterStats = FillSingleLetterStats(inputStream1);
IList<LetterStats> doubleLetterStats = FillDoubleLetterStats(inputStream2);

IList<LetterStats> singleLetterStats = FillSingleLetterStats(inputStream1);
IList<LetterStats> doubleLetterStats = FillDoubleLetterStats(inputStream2);
RemoveCharStatsByType(singleLetterStats, CharType.Vowel);
RemoveCharStatsByType(doubleLetterStats, CharType.Consonants);

RemoveCharStatsByType(singleLetterStats, CharType.Vowel);
RemoveCharStatsByType(doubleLetterStats, CharType.Consonants);
PrintStatistic(singleLetterStats);
PrintStatistic(doubleLetterStats);
}

PrintStatistic(singleLetterStats);
PrintStatistic(doubleLetterStats);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Ошибка.Файл не найден");
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка.{ex.Message}");
}
finally
{
Console.WriteLine("Нажмите любую клавишу, чтобы выйти");
Console.ReadKey(true);
}


// TODO : Необжодимо дождаться нажатия клавиши, прежде чем завершать выполнение программы.
}

/// <summary>
Expand All @@ -48,17 +76,37 @@ private static IReadOnlyStream GetInputStream(string fileFullPath)
/// <param name="stream">Стрим для считывания символов для последующего анализа</param>
/// <returns>Коллекция статистик по каждой букве, что была прочитана из стрима.</returns>
private static IList<LetterStats> FillSingleLetterStats(IReadOnlyStream stream)
{
{
var statDict=new Dictionary<string,LetterStats>();
stream.ResetPositionToStart();
while (!stream.IsEof)
{
char c = stream.ReadNextChar();
// TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - регистрозависимый.
char c;
try
{
c = stream.ReadNextChar();
}
catch (EndOfStreamException)
{
break;
}

if (!char.IsLetter(c))
{
continue;
}

string key = c.ToString();
if (statDict.TryGetValue(key, out var stat))
{
IncStatistic(stat);
}
else
{
statDict[key] = new LetterStats { Letter = key, Count = 1 };
}
}

//return ???;

throw new NotImplementedException();
return statDict.Values.ToList();
}

/// <summary>
Expand All @@ -70,16 +118,50 @@ private static IList<LetterStats> FillSingleLetterStats(IReadOnlyStream stream)
/// <returns>Коллекция статистик по каждой букве, что была прочитана из стрима.</returns>
private static IList<LetterStats> FillDoubleLetterStats(IReadOnlyStream stream)
{
var statDict=new Dictionary<string,LetterStats>();
char? prevC = null;
stream.ResetPositionToStart();
while (!stream.IsEof)
{
char c = stream.ReadNextChar();
// TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - НЕ регистрозависимый.
char c;
try
{
c = stream.ReadNextChar();
}
catch (EndOfStreamException)
{
break;
}

if(!char.IsLetter(c))
{
prevC=null;
continue;
}

char upperC=char.ToUpper(c);
if (prevC.HasValue && prevC.Value == upperC)
{
string pair = new string(new char[] { upperC, upperC });
if (statDict.TryGetValue(pair, out var stat))
{
IncStatistic(stat);
}
else
{
statDict[pair] = new LetterStats { Letter = pair, Count = 1 };
}
prevC=null;
}
else
{
prevC=upperC;
}


}

//return ???;

throw new NotImplementedException();
return statDict.Values.ToList();
}

/// <summary>
Expand All @@ -91,15 +173,40 @@ private static IList<LetterStats> FillDoubleLetterStats(IReadOnlyStream stream)
/// <param name="charType">Тип букв для анализа</param>
private static void RemoveCharStatsByType(IList<LetterStats> letters, CharType charType)
{
// TODO : Удалить статистику по запрошенному типу букв.
switch (charType)
for(int i=letters.Count-1; i >= 0; i--)
{
case CharType.Consonants:
break;
case CharType.Vowel:
break;
var charStat = letters[i];
if (string.IsNullOrEmpty(charStat.Letter))
{
continue;
}

bool isVowel = IsVowel(charStat.Letter[0] );
bool isRemove = true;

switch (charType)
{
case CharType.Consonants:
isRemove = !isVowel;
break;
case CharType.Vowel:
isRemove = isVowel;
break;
}

if (isRemove)
{
letters.RemoveAt(i);
}

}



}

private static bool IsVowel(char c)
{
return _vowels.Contains(char.ToUpper(c));
}

/// <summary>
Expand All @@ -111,8 +218,25 @@ private static void RemoveCharStatsByType(IList<LetterStats> letters, CharType c
/// <param name="letters">Коллекция со статистикой</param>
private static void PrintStatistic(IEnumerable<LetterStats> letters)
{
// TODO : Выводить на экран статистику. Выводить предварительно отсортировав по алфавиту!
throw new NotImplementedException();
if (letters == null)
{
return;
}

var sortLet=letters.OrderBy(x => x.Letter,StringComparer.Ordinal).ToList();
if (sortLet.Count == 0)
{
Console.WriteLine("нет данных");
return;
}

int allCount = 0;
foreach (var c in sortLet)
{
Console.WriteLine($"{c.Letter} : {c.Count}");
allCount+=c.Count;
}
Console.WriteLine($"ИТОГО: {allCount}");
}

/// <summary>
Expand Down
59 changes: 46 additions & 13 deletions TestTask/ReadOnlyStream.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
using System;
using System.IO;
using System.Runtime.Remoting.Channels;
using System.Text;

namespace TestTask
{
public class ReadOnlyStream : IReadOnlyStream
{
private Stream _localStream;
private StreamReader _localStream;

/// <summary>
/// Конструктор класса.
/// Т.к. происходит прямая работа с файлом, необходимо
/// обеспечить ГАРАНТИРОВАННОЕ закрытие файла после окончания работы с таковым!
/// </summary>
/// <param name="fileFullPath">Полный путь до файла для чтения</param>
public ReadOnlyStream(string fileFullPath)
///
public ReadOnlyStream(string fileFullPath): this (fileFullPath, Encoding.UTF8) { }
public ReadOnlyStream(string fileFullPath, Encoding enc)
{
IsEof = true;
if (string.IsNullOrWhiteSpace(fileFullPath))
{
throw new ArgumentNullException(nameof(fileFullPath),"Ошибка. Пустой путь до файла");
}
if(!File.Exists(fileFullPath))
{
throw new FileNotFoundException("Ошибка. Файл не найден",fileFullPath);
}

// TODO : Заменить на создание реального стрима для чтения файла!
_localStream = null;
_localStream = new StreamReader(fileFullPath, enc);
IsEof=_localStream.EndOfStream;
}

/// <summary>
/// Флаг окончания файла.
/// </summary>
public bool IsEof
{
get; // TODO : Заполнять данный флаг при достижении конца файла/стрима при чтении
get;
private set;
}

public void Dispose()
{
_localStream?.Dispose();
_localStream= null;
}

/// <summary>
/// Ф-ция чтения следующего символа из потока.
/// Если произведена попытка прочитать символ после достижения конца файла, метод
Expand All @@ -38,23 +55,39 @@ public bool IsEof
/// <returns>Считанный символ.</returns>
public char ReadNextChar()
{
// TODO : Необходимо считать очередной символ из _localStream
throw new NotImplementedException();
if (_localStream == null)
{
throw new ObjectDisposedException(nameof(ReadOnlyStream));
}
if (IsEof)
{
throw new EndOfStreamException("Коней файла");
}

int data = _localStream.Read();
if (data == -1)
{
IsEof = true;
throw new EndOfStreamException("Коней файла");
}

IsEof = _localStream.EndOfStream;
return (char)data;
}

/// <summary>
/// Сбрасывает текущую позицию потока на начало.
/// </summary>
public void ResetPositionToStart()
{
if (_localStream == null)
if(_localStream == null)
{
IsEof = true;
IsEof=true;
return;
}

_localStream.Position = 0;
IsEof = false;
_localStream.DiscardBufferedData();
_localStream.BaseStream.Seek(0,SeekOrigin.Begin);
IsEof = _localStream.EndOfStream;
}
}
}
Loading