Co będzie potrzebne? Generalnie niezbyt wiele - jak zbudowany jest dany format, biegłość w operowaniu na stringach, jakieś obycie z state machine oraz świadomość że w programowaniu również używa się ifów :) no i dyscyplina do pisania wielu testów
ale wyjdźmy z przykładami
Może akurat nie csv, xml czy json ale weźmy na warsztat zwykły kod
Kopiuj
namespace Test
public int Test(int a, int b)
{
if (a > b)
{
return a + b;
}
else
{
return a - b;
}
}
Na początku fajnie jakbyś zamienił tekst na jakąś abstrakcję - leksem / token / symbol / whatever
W podanym niżej podejściu prostu przechodzisz po tym inpucie i w zależności od złożoności formatu dodajesz jakąś logikę która to obsłuży, tu jakiś przykład:
Kopiuj
public List<LexElement> Walk()
{
Reset();
do
{
if (char.IsWhiteSpace(_Current))
_State = LexingState.WhiteCharacter;
else if (char.IsLetter(_Current))
_State = LexingState.Word;
else if (char.IsNumber(_Current))
_State = LexingState.NumericalValue;
else if (_Current == '"')
_State = LexingState.String;
else if (LexingFacts.OtherTokens.Contains(_Current))
_State = LexingState.Character;
else
_State = LexingState.Unknown;
Handle(_State);
} while (MoveNext());
return _Elements;
}
private void Handle(LexingState state)
{
switch(state)
{
case LexingState.Word:
HandleWord();
break;
case LexingState.String:
HandleString();
break;
case LexingState.NumericalValue:
HandleNumericalValue();
break;
case LexingState.Character:
HandleOtherCharacter();
break;
case LexingState.WhiteCharacter:
HandleWhiteCharacter();
break;
case LexingState.Unknown:
throw new Exception("Unrecognized token");
}
}
private void HandleString()
{
var tmp = "";
while (MoveNext())
{
if (_Current == '"' && HasPreviousElement() && ElementAt(_Index - 1) != LexingFacts.EscapeChar)
{
var element = new LexStringLiteral(tmp, GetDiagnostics());
_Elements.Add(element);
return;
}
tmp += _Current;
}
Error("Unclosed string");
}
private void HandleWord()
{
var tmp = "";
void AddElement()
{
LexElement element;
if (LanguageFacts.KeywordMapper.TryGetValue(tmp, out var lexingElement))
{
element = new LexKeyword(tmp, lexingElement, GetDiagnosticsAtIndex(tmp.Length));
}
else
{
element = new LexWord(tmp, GetDiagnosticsAtIndex(tmp.Length));
}
_Elements.Add(element);
}
do
{
if (char.IsWhiteSpace(_Current) || IsLast())
{
if (IsLast()) tmp += _Current;
AddElement();
if (!IsLast())
MoveBehind();
return;
}
if (LexingFacts.OtherTokens.Contains(_Current))
{
AddElement();
MoveBehind();
return;
}
tmp += _Current;
} while (MoveNext());
}
i np. po czymś takim dostajesz listę już nie znaczków, a czegoś co już ma konkretniejsze znaczenie np.
Kopiuj
Keyword: namespace of Kind: Namespace
Word: Test
Keyword: public of Kind: AccessibilityModifier
Keyword: int of Kind: Type
Word: Test
Character: OpenParenthesis
Keyword: int of Kind: Type
Word: a
Character: Comma
Keyword: int of Kind: Type
Word: b
Character: ClosedParenthesis
Character: OpenBracket
Gdy już masz taką wstępnie przetworzoną warstwę na której łatwiej ci będzie operować, to teraz wypadałoby zrobić to, co tam potrzebujesz
w przypadku CSV to pewnie będzie budowanie obiektów, a w przypadku języku programowania budowa np. drzewka
Kopiuj
|-Root
| \-Namespace: 'Test'
| \-TypedFunction: 'Test'(int32). Args: (int32), (int32).
| \-Body
| \-TypedIf - ComplexTyped: bool; Operator: GreaterThan
| |-Body
| | \-TypedReturnStatement
| | \-ComplexTyped: int32; Operator: Addition
| | |-Typed Variable Use: a
| | \-Typed Variable Use: b
| \-Body
| \-TypedReturnStatement
| \-ComplexTyped: int32; Operator: Substraction
| |-Typed Variable Use: a
| \-Typed Variable Use: b
ale to już się o wiele bardziej komplikuje i wymaga praktyki
więc pewnie jakbyś wyszedł od prostych formatów typu ini, później jakieś csvki mniej oraz bardziej skomplikowane (np. wartości ze średnikami oraz znakami nowej linii, etc)
podstawowy css może, jakiś podzbiór html/xml, następnie może json?