mercredi 11 décembre 2024

Parser CSV or FixedWidthFormat

 en C#, write code that can import the content of the input text files to the common data format used by the analysis. The solution should be extensible to handle others formats and display good object oriented principles. Content that does strictly adhere to either of the two formats should be reject with the message The input is not in a valid format. Read input content using Console.ReadLine().Write output to Console.A number of externally sourced text files are required to provide a complete set of data for some business analysis. The content of each file is considered to be the input to the program as a string array with each line being an element of the array. The content maybe in CSV or FixedWidth format. The target format of the output is serialised JSON with all white space removed. The source and target data schemas are mapped as follows: (Target Output Field, Datatype, CSV input field, fixed width input field) have: (OriginalSourceId, String, Ref, characters 1-4), (TransactionDate, DateTime, Date, characters 5-14), (Value, Decimal, Amount, characters 15-22), (Rate, Decimal, Rate, characters 23-27)


using System;

using System.Collections.Generic;

using System.Globalization;

using System.Linq;

using System.Text.Json;

using System.Text.Json.Serialization;


class Program

{

    public static void Main(string[] args)

    {

        Console.WriteLine("Enter the input content line by line, and type 'END' to finish:");


        List<string> inputLines = new();

        string line;

        while ((line = Console.ReadLine()) != "END")

        {

            inputLines.Add(line);

        }


        try

        {

            // Parse the input using a factory method to determine the format

            var parser = ParserFactory.GetParser(inputLines);

            var records = parser.Parse(inputLines);


            // Serialize the list of records with a custom JSON converter

            var jsonOptions = new JsonSerializerOptions

            {

                WriteIndented = false,

                Converters = { new DateTimeConverter() }

            };

            string jsonArray = JsonSerializer.Serialize(records, jsonOptions);


            // Add curly braces around the array to match the exact format

            string jsonOutput = "{[" + jsonArray.TrimStart('[').TrimEnd(']') + "]}";


            Console.WriteLine(jsonOutput);

        }

        catch (Exception ex)

        {

            Console.WriteLine(ex.Message);

        }

    }

}


// Define a custom DateTime converter

public class DateTimeConverter : JsonConverter<DateTime>

{

    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

    {

        return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture);

    }


    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)

    {

        writer.WriteStringValue(value.ToString("yyyy-MM-dd"));

    }

}


// Define a common record format for output

public class Record

{

    public string OriginalSourceId { get; set; }

    public DateTime TransactionDate { get; set; }

    public decimal Value { get; set; }

    public decimal Rate { get; set; }

}


// Define the base parser interface

public interface IParser

{

    List<Record> Parse(List<string> inputLines);

}


// CSV Parser Implementation

public class CsvParser : IParser

{

    public List<Record> Parse(List<string> inputLines)

    {

        var records = new List<Record>();


        foreach (var line in inputLines)

        {

            var fields = line.Split(',');

            if (fields.Length != 4)

                throw new FormatException("The input is not in a valid format.");


            records.Add(new Record

            {

                OriginalSourceId = fields[0].Trim(),

                TransactionDate = DateTime.ParseExact(fields[1].Trim(), "yyyy-MM-dd", CultureInfo.InvariantCulture),

                Value = decimal.Parse(fields[2].Trim(), CultureInfo.InvariantCulture),

                Rate = decimal.Parse(fields[3].Trim(), CultureInfo.InvariantCulture)

            });

        }


        return records;

    }

}


// Fixed Width Parser Implementation

public class FixedWidthParser : IParser

{

    public List<Record> Parse(List<string> inputLines)

    {

        var records = new List<Record>();


        foreach (var line in inputLines)

        {

            if (line.Length < 27)

                throw new FormatException("The input is not in a valid format.");


            records.Add(new Record

            {

                OriginalSourceId = line.Substring(0, 4).Trim(),

                TransactionDate = DateTime.ParseExact(line.Substring(4, 10).Trim(), "yyyy-MM-dd", CultureInfo.InvariantCulture),

                Value = decimal.Parse(line.Substring(14, 8).Trim(), CultureInfo.InvariantCulture),

                Rate = decimal.Parse(line.Substring(22, 5).Trim(), CultureInfo.InvariantCulture)

            });

        }


        return records;

    }

}


// Factory to determine the correct parser

public static class ParserFactory

{

    public static IParser GetParser(List<string> inputLines)

    {

        if (inputLines == null || !inputLines.Any())

            throw new ArgumentException("The input is not in a valid format.");


        // Check the format of the first line

        var firstLine = inputLines.First();


        if (firstLine.Contains(","))

        {

            return new CsvParser();

        }

        else if (firstLine.Length >= 27)

        {

            return new FixedWidthParser();

        }

        else

        {

            throw new FormatException("The input is not in a valid format.");

        }

    }

}


public static int firstOccurrence(string text, string searchPattern)

 en C#, On 'a deux paramètres de type string "s" et "x", Nous devrons retourner la l'indice de la première occurrence de x sur s. the "x" may include a signle wildcard character '*' which matches any one character. Implementation function public static int firstOccurrence(string text, string searchPattern)


using System;


class Program

{

    public static void Main(string[] args)

    {

        string text = "Bonjour tout le monde";

        string searchPattern = "t*ut";


        int index = firstOccurrence(text, searchPattern);

        Console.WriteLine($"L'indice de la première occurrence de \"{searchPattern}\" dans \"{text}\" est : {index}");

    }


    public static int firstOccurrence(string text, string searchPattern)

    {

        if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(searchPattern))

            return -1; // Entrée invalide.


        int textLength = text.Length;

        int patternLength = searchPattern.Length;


        if (patternLength > textLength)

            return -1; // Le motif ne peut pas être trouvé si sa longueur dépasse celle du texte.


        // Parcourir le texte avec une fenêtre de la taille du motif

        for (int i = 0; i <= textLength - patternLength; i++)

        {

            bool match = true;


            for (int j = 0; j < patternLength; j++)

            {

                // Vérifier la correspondance ou le caractère générique '*'

                if (searchPattern[j] != '*' && text[i + j] != searchPattern[j])

                {

                    match = false;

                    break;

                }

            }


            if (match)

                return i; // Retourner l'indice de la première correspondance.

        }


        return -1; // Aucune correspondance trouvée.

    }

}


static int FindParent(int processNumber)

 en C#, Un arbre où chaque numéro parent est le nombre d'enfants, en respectant l'ordre. Par exemple, le nœud 1 a un seul enfant, nommé 2. Le nœud 2 a deux enfants, nommés 3 et 4. Le nœud 3 a trois enfants, nommés 5, 6 et 7. Le nœud 4 a quatre enfants, nommés 8, 9, 10 et 11. Le nœud 5 a cinq enfants, nommés 12, 13, 14, 15 et 16. Et ainsi de suite. Le besoin ici c'est de retourner le ProcessNumber du parent à partir d'un ProcessNumber donné.



using System;


class Program

{

    static void Main(string[] args)

    {

        int processNumber = 13; // Exemple d'entrée

        int parent = FindParent(processNumber);

        Console.WriteLine($"Le parent du nœud {processNumber} est : {parent}");

    }


    static int FindParent(int processNumber)

    {

        if (processNumber == 1)

            return -1; // Le nœud racine n'a pas de parent.


        int current = 1; // Numéro actuel du nœud.

        int start = 2; // Premier numéro d'enfant.


        while (start <= processNumber)

        {

            int end = start + current - 1; // Dernier numéro d'enfant pour le nœud actuel.

            if (processNumber >= start && processNumber <= end)

                return current;


            current++; // Passer au nœud suivant.

            start = end + 1; // Mettre à jour la plage des enfants pour le prochain nœud.

        }


        return -1; // Si aucun parent n'est trouvé (ne devrait pas arriver si les données sont valides).

    }

}





===========================



static int FindParent(int processNumber)
{
    if (processNumber == 1)
        return -1; // Le nœud racine n'a pas de parent.

    int start = 2; // Premier numéro d'enfant.

    for (int current = 1; start <= processNumber; current++)
    {
        int end = start + current - 1; // Dernier numéro d'enfant pour le nœud actuel.

        if (processNumber >= start && processNumber <= end)
            return current;

        start = end + 1; // Mettre à jour la plage des enfants pour le prochain nœud.
    }

    return -1; // Si aucun parent n'est trouvé (ne devrait pas arriver si les données sont valides).
}