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
28 changes: 28 additions & 0 deletions TestTask/Extensions/CharInvariantCompareExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace TestTask.Extensions;

public static class CharInvariantCompareExtension
{
/// <summary>
/// Проверка символов без учета регистра.
/// </summary>
/// <param name="c1">Символ, относительно которого сравниваем.</param>
/// <param name="c2">Символ сравнения.</param>
/// <param name="ignoreCase">Учитывать ли регистр.</param>
public static bool EqualsWithCaseOption(this char c1, char c2, bool ignoreCase = false)
{
if (ignoreCase)
return c1.ToLowerInvariant().Equals(c2.ToLowerInvariant());

return c1.Equals(c2);
}

/// <summary>
/// Приведение к нижнему регистру.
/// </summary>
/// <param name="c">Символ приведения.</param>
/// <returns></returns>
public static char ToLowerInvariant(this char c)
{
return char.ToLowerInvariant(c);
}
}
21 changes: 21 additions & 0 deletions TestTask/Extensions/CharStreamExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using TestTask.Interfaces;

namespace TestTask.Extensions;

internal static class CharStreamExtension
{
/// <summary>
/// Проходит по потоку и находит первый символ являющийся буквой по Unicode.
/// </summary>
/// <param name="stream">Поток текста.</param>
/// <returns>Буква или символ новой строки(конец потока).</returns>
public static char GetNextLetter(this IReadOnlyStream stream)
{
char c = '\0';

while (!stream.IsEof && !char.IsLetter(c))
c = stream.ReadNextChar();

return c;
}
}
36 changes: 36 additions & 0 deletions TestTask/Extensions/ConsonantVowelClassificator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace TestTask.Extensions;
/// <summary>
/// Классификатор гласных и согласных. Определяет русские и английские буквы. Откидывает мягкий и твердый знаки.
/// </summary>
public static class ConsonantVowelClassificator
{
private static readonly HashSet<char> Vowels = new HashSet<char>("аеёиоуыэюяАЕЁИОУЫЭЮЯaeiouAEIOU");
private static readonly HashSet<char> UncategorizedChars = new HashSet<char>("ьъЬЪ");

/// <summary>
/// Является ли гласной.
/// </summary>
/// <param name="c">Проверяемый символ</param>
/// <returns></returns>
public static bool IsVowel(char c)
{
if (!char.IsLetter(c))
return false;
if (UncategorizedChars.Contains(c))
return false;
return Vowels.Contains(c);
}
/// <summary>
/// Является ли согласной.
/// </summary>
/// <param name="c">Проверяемый символ</param>
/// <returns></returns>
public static bool IsConsonant(char c)
{
if (!char.IsLetter(c))
return false;
if (UncategorizedChars.Contains(c))
return false;
return !Vowels.Contains(c);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
namespace TestTask
{
/// <summary>
/// Интерфейс для работы с файлом в сильно урезаном виде.
/// Умеет всего 2 вещи: прочитать символ, и перемотать стрим на начало.
/// </summary>
internal interface IReadOnlyStream
{
// TODO : Необходимо доработать данный интерфейс для обеспечения гарантированного закрытия файла, по окончанию работы с таковым!
char ReadNextChar();

void ResetPositionToStart();

bool IsEof { get; }
}
}
namespace TestTask.Interfaces
{
/// <summary>
/// Интерфейс для работы с файлом в сильно урезаном виде.
/// Умеет всего 2 вещи: прочитать символ, и перемотать стрим на начало.
/// </summary>
public interface IReadOnlyStream : IDisposable
{
char ReadNextChar();

void ResetPositionToStart();

bool IsEof { get; }
}
}
18 changes: 0 additions & 18 deletions TestTask/LetterStats.cs

This file was deleted.

36 changes: 18 additions & 18 deletions TestTask/CharType.cs → TestTask/Models/CharType.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
namespace TestTask
{
/// <summary>
/// Тип букв
/// </summary>
public enum CharType
{
/// <summary>
/// Гласные
/// </summary>
Vowel,
/// <summary>
/// Согласные
/// </summary>
Consonants
}
}
namespace TestTask.Models
{
/// <summary>
/// Тип букв
/// </summary>
public enum CharType
{
/// <summary>
/// Гласные
/// </summary>
Vowel,

/// <summary>
/// Согласные
/// </summary>
Consonants
}
}
7 changes: 7 additions & 0 deletions TestTask/Models/LetterStats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TestTask.Models
{
/// <summary>
/// Статистика вхождения буквы/пары букв
/// </summary>
public record struct LetterStats (string Letter, int Count = 0);
}
134 changes: 41 additions & 93 deletions TestTask/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using TestTask.Extensions;
using TestTask.Interfaces;
using TestTask.Models;
using TestTask.Services;
using TestTask.Services.LetterStrategy;

namespace TestTask
{
public class Program
internal static class Program
{

/// <summary>
/// Программа принимает на входе 2 пути до файлов.
/// Анализирует в первом файле кол-во вхождений каждой буквы (регистрозависимо). Например А, б, Б, Г и т.д.
Expand All @@ -16,70 +20,44 @@ public class Program
/// Второй параметр - путь до второго файла.</param>
static void Main(string[] args)
{
IReadOnlyStream inputStream1 = GetInputStream(args[0]);
IReadOnlyStream inputStream2 = GetInputStream(args[1]);

IList<LetterStats> singleLetterStats = FillSingleLetterStats(inputStream1);
IList<LetterStats> doubleLetterStats = FillDoubleLetterStats(inputStream2);

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

PrintStatistic(singleLetterStats);
PrintStatistic(doubleLetterStats);

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

/// <summary>
/// Ф-ция возвращает экземпляр потока с уже загруженным файлом для последующего посимвольного чтения.
/// </summary>
/// <param name="fileFullPath">Полный путь до файла для чтения</param>
/// <returns>Поток для последующего чтения.</returns>
private static IReadOnlyStream GetInputStream(string fileFullPath)
{
return new ReadOnlyStream(fileFullPath);
}

/// <summary>
/// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения каждой буквы.
/// Статистика РЕГИСТРОЗАВИСИМАЯ!
/// </summary>
/// <param name="stream">Стрим для считывания символов для последующего анализа</param>
/// <returns>Коллекция статистик по каждой букве, что была прочитана из стрима.</returns>
private static IList<LetterStats> FillSingleLetterStats(IReadOnlyStream stream)
{
stream.ResetPositionToStart();
while (!stream.IsEof)
if (args.Length < 2)
{
char c = stream.ReadNextChar();
// TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - регистрозависимый.
Console.WriteLine("Использование: TestTask <путь_к_файлу1> <путь_к_файлу2>");
return;
}

//return ???;

throw new NotImplementedException();
}

/// <summary>
/// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения парных букв.
/// В статистику должны попадать только пары из одинаковых букв, например АА, СС, УУ, ЕЕ и т.д.
/// Статистика - НЕ регистрозависимая!
/// </summary>
/// <param name="stream">Стрим для считывания символов для последующего анализа</param>
/// <returns>Коллекция статистик по каждой букве, что была прочитана из стрима.</returns>
private static IList<LetterStats> FillDoubleLetterStats(IReadOnlyStream stream)
{
stream.ResetPositionToStart();
while (!stream.IsEof)
try
{
char c = stream.ReadNextChar();
// TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - НЕ регистрозависимый.
IList<LetterStats> singleLetterStats;
IList<LetterStats> doubleLetterStats;

using (IReadOnlyStream inputStream1 = new ReadOnlyStream(args[0]))
{
singleLetterStats = LetterStatsService.FillSingleLetterStats(inputStream1);
}
using (IReadOnlyStream inputStream2 = new ReadOnlyStream(args[1]))
{
doubleLetterStats = LetterStatsService.FillDoubleLetterStats(inputStream2);
}

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

LetterStatisticsPrintHelper.PrintStatisticSorted(singleLetterStats);
LetterStatisticsPrintHelper.PrintStatisticSorted(doubleLetterStats);
}
catch (FileNotFoundException e)
{
Console.WriteLine($"Файл не найден: {e.FileName}");
}
catch (Exception e)
{
Console.WriteLine($"Ошибка: {e.Message}");
}
finally
{
Console.ReadKey();
}

//return ???;

throw new NotImplementedException();
}

/// <summary>
Expand All @@ -91,39 +69,9 @@ private static IList<LetterStats> FillDoubleLetterStats(IReadOnlyStream stream)
/// <param name="charType">Тип букв для анализа</param>
private static void RemoveCharStatsByType(IList<LetterStats> letters, CharType charType)
{
// TODO : Удалить статистику по запрошенному типу букв.
switch (charType)
{
case CharType.Consonants:
break;
case CharType.Vowel:
break;
}

var strategy = CharFilterStrategyFactory.GetStrategy(charType);
letters.RemoveElementsByStrategy(strategy);
}

/// <summary>
/// Ф-ция выводит на экран полученную статистику в формате "{Буква} : {Кол-во}"
/// Каждая буква - с новой строки.
/// Выводить на экран необходимо предварительно отсортировав набор по алфавиту.
/// В конце отдельная строчка с ИТОГО, содержащая в себе общее кол-во найденных букв/пар
/// </summary>
/// <param name="letters">Коллекция со статистикой</param>
private static void PrintStatistic(IEnumerable<LetterStats> letters)
{
// TODO : Выводить на экран статистику. Выводить предварительно отсортировав по алфавиту!
throw new NotImplementedException();
}

/// <summary>
/// Метод увеличивает счётчик вхождений по переданной структуре.
/// </summary>
/// <param name="letterStats"></param>
private static void IncStatistic(LetterStats letterStats)
{
letterStats.Count++;
}


}
}
36 changes: 0 additions & 36 deletions TestTask/Properties/AssemblyInfo.cs

This file was deleted.

Loading