Skip to content

Conversation

@Kpokoko
Copy link

@Kpokoko Kpokoko commented Nov 3, 2025

Написал первоначальную предполагаемую структуру парсера @OvchinnikovNikita

@@ -0,0 +1,24 @@
namespace Markdown;

public class Md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Плохое название, давай поменяем

@@ -0,0 +1,9 @@
namespace Markdown;

public class Token

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Напишу здесь, но относится и к другим аналогичным местам: используй свойства вместо полей, например: public int StartIndex { get; set; }


public enum TokenType
{
Italics = 0,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Italic
  2. Обычно нулевой элемент оставляют для значений по типу Unknown - это помогает избежать ошибок, связанных с проставлением значения по умолчанию. Давай здесь сделаем также

@@ -0,0 +1,8 @@
namespace Markdown;

public enum TokenType

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum автоматически номеруется с нуля и далее по натуральным числам, обычно так явно не прописывают, только если не хотят явно изменить нумерацию. Здесь явно указана стандартная нумерация, поэтому, в целом, можно убрать. Править не заставляю - опционально. Если так привычнее - оставь

@@ -0,0 +1,24 @@
namespace Markdown;

public class Md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай вынесем все эти методы в интерфейс, и сделаем класс Md (не забудь поменять название) имплементацией этого интерфейса. Придумай соответствующее название для интерфейса

@@ -0,0 +1,10 @@
namespace Markdown;

public interface IParser

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IParser - обобщенное название, но методы выставлены довольно специфичные, ещё и метод Parse, который, логично, должен выставлять парсер, отсутствует, зато есть метод Render) В реальном проекте это будет страшно путать других разработчиков, которые впервые видят этот код. Давай разберёмся с названиями


public class MarkdownParser : IParser
{
private static Dictionary<string, TokenType> _pairMarkdownToTag = new()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сделай readonly


private string _markdown;

public void SetMarkdownText(string markdown) => this._markdown = markdown; // Только для теста обёртки токенов в теги

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты здесь нарушаешь инкапсуляцию, устанавливая состояние парсера извне ради тестов - плохая практика. Давай от этого избавимся, но чтобы тест работал. Например, попробуй подумать над тем, чтобы передавать markdown явно в WrapTokensWithTags или что-то другое придумай

}
else
currentTag = markdown[i].ToString();
if (currentTag == "#")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это условие никогда не выполняется - в _pairMarkdownToTag отсутствует #

token.StartIndex - currEndIndex));
if (token.StartIndex >= currEndIndex)
htmlString.Append(wrappedTags[i]);
else

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Код в блоке else работает неэффективно и реализация через replace может быть довольно хрупкой. Лучше строить HTML за один проход без замен, подумай, как избавиться от этих проблем

&& (start > 1 && _markdown[start - 2] != '\\');
if (isOpeningTag)
return !isTagScreened && _markdown[start + length] != ' '
|| (_markdown[start] == '#' && _markdown[start] == '#' && _markdown[start + 1] == ' ');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аналогично, условие `_markdown[start] == '#' бесполезное

return !isTagScreened && _markdown[start + length] != ' '
|| (_markdown[start] == '#' && _markdown[start] == '#' && _markdown[start + 1] == ' ');
return !isTagScreened && _markdown[start - 1] != ' '
|| (_markdown[start] == '#' && start + length <= _markdown.Length && _markdown[start + 1] == ' ');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аналогично

return !string.IsNullOrEmpty(_markdown.Substring(start, end - start + 1));
}

public bool HasTagDigitsInside(int start, int end)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Посмотри на название метода и на возвращаемое значение в return. Ничего не смущает?)

@@ -0,0 +1,7 @@
// public class Program

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

На всякий случай напишу: в реальный проект такие изменения закомментированные без пояснений лучше не заливать)

case "Title":
return (Header.OpeningTag, Header.ClosingTag);
case "ListItem":
return (ListItem.OpeningTag, ListItem.OpeningTag);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Дважды ListItem.OpeningTag - очепятка

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кстати в действительности этот сценарий - мертвый код, т.к. списки обрабатываются в ProcessUnpairLineTags. Ещё один минус в копилку ProcessUnpairLineTags

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants