Separate string by amount of characters

I am developing a component to read the file sent by DataPrev with the ratio of monthly obituaries. This file is a txt and every 210 characters is a different person.

Documentation can be viewed at this link: SISOBI .

I'm used to separating data like this through a delimiter, using Split(), but this one in particular has none, and is separated by amount of characters.

I did the Action to send the file txt to the application, and read the data contained in it.

Ex:

string exemplo = "13032015joao";

From this string , I need to withdraw the data and put in variables, like:

int dia = 13;
int mes = 03;
int ano = 2015;
string nome = joao;

The amount of character is fixed, example:

Day will always be 2 characters, and after it will always come the month with 2 characters, and after the year... And so until you finish the 210 characters.

Using Split() if you had a delimiter would look something like this:

var exemplo = "13|03|2015|joao";
 string[] stringSeparators = new string[] { "|" };
            var result = nomeDescrypt.Split(stringSeparators, StringSplitOptions.None);

var dia = Convert.ToInt32(result[0]);
var Mes= Convert.ToInt32(result[1]);
var Ano= Convert.ToInt32(result[2]);
var Nome= Convert.ToInt32(result[3]);

My question is: how to separate a string , delimiting by amount of characters?

My controller to read the file looks like this:

[HttpPost]
        public ActionResult Index(HttpPostedFileBase file)
        {
            //verifica se o arquivo está nulo
            if (file == null)
            {
                TempData["MensagemError"] = "Erro ao realizar o upload do arquivo!";
                return View("Index");
            }

            //Salvar o arquivo txt
            string path = Path.Combine(Server.MapPath("~/App_Data/Uploads/" + file.FileName));
            file.SaveAs(path);

            //Realiza a leitura do arquivo txt
            var fileContents = System.IO.File.ReadAllText(path);

            //testar se está lendo o arquivo
        TempData["Mensagem"] = fileContents;

            return RedirectToAction("Index");
        }

Layot example:

000028000280000016427201412310000000000MARCIO SEARA RIBEIRO                                                        MARIA PETANIA DE OLIVEIRA SEARA 19780306201412319442067052500000000000000000000007657          
000028000290000016428201412310000000000MAIRE VALENTIM DA SILVA                                                     MAIRE VALENTIM DA SILVA         19281105201412310387867350700000000000000000000007657  
Author: Maniero, 2015-03-13

1 answers

The method you are looking for is Substring:

using static System.Convert;
using static System.Console;
                    
public class Program {
    public static void Main() {
        var exemplo = "13032015joao";
        var dia = ToInt32(exemplo.Substring(0, 2));
        var mes = ToInt32(exemplo.Substring(2, 2));
        var ano = ToInt32(exemplo.Substring(4, 4));
        var nome = exemplo.Substring(8);
        WriteLine(dia);
        WriteLine(mes);
        WriteLine(ano);
        WriteLine(nome);
    }
}

See working on ideone. And no .NET Fiddle. Also I put on GitHub for future reference .

You can do a few things to automate code execution. It may get shorter and generalized, but the logic is a bit more complex. For reference only the most generic form:

using System;
using static System.Console;
using System.Collections.Generic;
                    
public class Program {
    public static void Main() {
        var exemplo = "13032015joao";
        //o último elemento poderia ser 200, por exemplo
        //o que se for garantido que ele tenha o tamanho, evitaria o if no método
        var partes = SplitFixed(exemplo, new List<int>() {2, 2, 4, 0});
        foreach(var parte in partes) {
            WriteLine(parte);
        }
        //poderia fazer as conversões aqui e jogar nas variáveis individuais
        
        //alternativa com tipos, não sei se compensa o esforço
        //para fazer certo daria o mesmo trabalho que fazer manualmente
        //poucos casos esta forma seria realmente mais vantajosa e o ideal é que a conversão
        //fosse feita através de lambdas contendo o código de conversão e não com tipos
        var partes2 = SplitFixedTyped(exemplo, new List<Tuple<int, Type>>() {
            new Tuple<int, Type>(2, typeof(int)), 
            new Tuple<int, Type>(2, typeof(int)),
            new Tuple<int, Type>(4, typeof(int)),
            new Tuple<int, Type>(0, typeof(string))});
        foreach(var parte in partes2) {
            WriteLine("Dado: {0} - Tipo {1}", parte, parte.GetType());
        }
        
    }
    public static List<String> SplitFixed(string texto, List<int> tamanhos) {
        var partes = new List<String>();
        var posicao = 0;
        foreach(var tamanho in tamanhos) {
            if (tamanho > 0) { //padronizei que 0 significa que deve ir até o fim
                partes.Add(texto.Substring(posicao, tamanho));
            } else {
                // o ideal é que não tenha essa parte e todos os tamanhos sejam definidos
                //o 0 só pode ser usado como último parâmetro.
                partes.Add(texto.Substring(posicao));
            }
            posicao += tamanho;
        }
        return partes;
    }
    //esta implementação é um pouco ingênua, não funciona em todas as situações mas funciona com o básico
    public static List<object> SplitFixedTyped(string texto, List<Tuple<int, Type>> tamanhos) {
        var partes = new List<object>();
        var posicao = 0;
        foreach(var tamanho in tamanhos) {
            if (tamanho.Item1 > 0) { //padronizei que 0 significa que deve ir até o fim
                partes.Add(Convert.ChangeType(texto.Substring(posicao, tamanho.Item1), tamanho.Item2));
            } else {
                // o ideal é que não tenha essa parte e todos os tamanhos sejam definidos
                //o 0 só pode ser usado como último parâmetro.
                partes.Add(texto.Substring(posicao));
            }
            posicao += tamanho.Item1;
        }
        return partes;
    }
}

See working on Ideon. And no .NET Fiddle. Also I put on GitHub for future reference .

A generic solution can be useful if you have to deal with multiple fixed-size column files with different layout . But when going to do something generic have to think Well of all the possibilities, it is good to ensure that the parameters are in order. I did it quickly without considering everything that can happen.

At the time that I did not exist Span and tuples by value as they exist today, so this code can be optimized.

 8
Author: Maniero, 2020-09-22 15:26:38