Como dividir um arquivo CSV em vários arquivos com base em uma cadeia de texto?

6

Eu tenho vários arquivos de texto (CSV) com uma estrutura semelhante a esta:

funkiana,23.55,-99.866
funkiana,24.634,-98.701
funkiana,24.717,-98.901
geminiflora,22.25,-104.6166667
geminiflora,21.21666667,-104.65
horrida,19.633,-97.367
horrida,23.61666667,-102.575
horrida,22.158,-100.979
horrida,19.506,-97.433
horrida,17,-97.56667
horrida,19.485,-97.263
horrida,19.017,-99.133
horrida,19.017,-99.15
horrida,18.91,-99.23
horrida,17.82167,-100.26333
horrida,19.507,-97.438
inaequidens,19.399,-99.314
inaequidens,23.58333,-105.8833
inaequidens,19.767,-103.7
inaequidens,20.787,-103.848

Como você pode ver, existem três campos (espécie, latitude e longitude). Agora, quero dividir cada arquivo CSV em arquivos CSV diferentes, contendo apenas os dados de cada espécie. Em outras palavras, eu quero um arquivo para todas as ocorrências de funkiana (com lat / lon), outro para geminiflora (com lat / lon) e assim por diante.

Alguma idéia de como fazer isso? Talvez com um script ou uma macro do Excel?

    
por Kureno 01.08.2015 / 03:03

3 respostas

7

O método mais rápido que eu consegui pensar é usar o PowerShell

$fullpath = "D:\myFolder\input.csv"

$path = Split-Path $fullpath -parent
$data = Import-CSV -Delimiter "," -Path $fullpath -Header species,latitude,longitude  

foreach ($group in $data | Group species){        
    $data | Where-Object {$_.species -eq $group.name} | 
        ConvertTo-Csv -NoTypeInformation | 
        foreach {$_.Replace('"','')} | 
        Out-File "$path\$($group.name).csv"     
}
  1. Cole o código em um novo arquivo de texto e salve-o como, por exemplo, MySplitMacro.ps1
  2. Edite a primeira linha e altere $fullpath para o caminho CSV desejado
  3. Clique com o botão direito do mouse no arquivo .ps1 e clique em Executar com o PowerShell

Tomando seu exemplo inicial como entrada, o script criará 4 novos arquivos CSV no mesmo local que seu arquivo de entrada. Cada CSV conterá um conjunto de entradas quando filtrado pela primeira coluna.

Exemplo de pasta resultante

Um arquivo de exemplo resultante

Ajustes

  • Altereespécieem$data|Groupspeciesparadefiniracolunaafiltrar
  • Altere-Delimiter"," se o seu arquivo de entrada tiver um delimitador diferente, como guias "'t" ou ponto-e-vírgula ";"
  • Altere -Header species,latitude,longitude para os nomes das colunas. Encomende-o corretamente
  • Altere $path\$($group.name).csv se você precisar de um caminho de saída diferente
  • Em vez de -eq $group.name para filtrar seus resultados, você também pode usar -like *$group.name* para comparação de curingas ou -match '[A-Z]$group.name' para RegEx comparação

Recursos usados

por 01.08.2015 / 06:49
0

O que você está pedindo é comumente chamado de processo de "quebra de controle". Existe um valor de "controle". No seu caso, é a espécie. Quando isso muda valores ou "breaks", queremos fazer alguma coisa. No seu caso, você quer escrever um novo arquivo.

Existem várias maneiras de resolver seu problema. Eu normalmente usaria uma linguagem de script vs. o Excel para resolvê-la.

Este link tem um passo a passo se você estiver interessado em aprender como escrever um programa / script como: link

Se você está em uma plataforma Windows e não se importa em usar uma linguagem de programação, você pode usar o LinqPad ( link ) que tem uma edição gratuita e o seguinte programa C # (certifique-se de selecionar "C # program" no menu suspenso Language do LinqPad):

void Main()
{
    var path = @"c:\sourceGit\speciesLatLon.txt";
    var inputLines = File.ReadAllLines(path);

    // Holds all the lines to be added to each output file
    var linesForCurrentSpeciesFile = new List<string>(); 

    // Read first row
    int i = 0;
    var currentSpecies = GetSpecies(inputLines[i]);

    // initialize hold value
    var holdValue = currentSpecies;

    // Initialize output values
    linesForCurrentSpeciesFile.Add(inputLines[i]);

    // Read next value
    i++;

    while( i < inputLines.Length )
    {
        currentSpecies = GetSpecies(inputLines[i]);
        if (currentSpecies !=  holdValue)
        {
            // output current file
            WriteSpeciesFile(holdValue, linesForCurrentSpeciesFile);

            // Initialize new output file by clearing out the previous
            linesForCurrentSpeciesFile.Clear();

            // update hold value with the value just examined.
            holdValue = currentSpecies;
        }
        // Add the current line to the output file
        linesForCurrentSpeciesFile.Add(inputLines[i]);
        i++;
    }
    // Write the output file because last row is equal to a break in the sequence
    WriteSpeciesFile(currentSpecies, linesForCurrentSpeciesFile);
}

// Define other methods and classes here
public string GetSpecies(string line)
{
    // return the first value of the input line
    return line.Split(new char[] {','})[0];
}

public void WriteSpeciesFile(string species, List<string> content)
{
    File.WriteAllLines(string.Format(@"C:\sourceGit\{0}.csv", species), content.ToArray());
}
    
por 01.08.2015 / 05:21
0

Um aplicativo de pesquisa csv simples como o CsvFileSearch fará isso sem a necessidade de ficar complicado. Ele pesquisará vários arquivos e salvará os resultados em outro arquivo.

    
por 27.08.2015 / 20:42