Arquivo em lote recursivo

0

Eu tenho um arquivo que parece assim:

head1,head2,head3,head4,head5,head6
a11,a12,keyA,a14,a15,a16
a21,a22,keyB,a24,a25
a31,a32,keyC,a34
a41,a42,keyB,a44,a44
a51,a52,keyA,a54,a55,a56
a61,a62,keyA,a64,a65,a66
a71,a72,keyC,a74
some message

Objetivo: Gravar lista de chaves exclusivas para um arquivo de texto. Por exemplo, o resultado do arquivo descrito acima deve ser:

keyA, keyB, keyC

Aqui está o pseudocódigo que gostaria de implementar no arquivo de lote recur.bat

  1. Leia a segunda linha do arquivo de entrada
  2. Se não houver chave na segunda linha, retorne mais continuar
  3. Anexar keyX à lista
  4. FINDSTR /v keyX inputfile
  5. Resultados do tubo para recur.bat

Não sei se essa é a maneira mais eficiente de fazer isso sem usar a linguagem de programação real.

Alguma sugestão para o código real do arquivo de lote?

    
por MCZ 24.10.2012 / 11:08

3 respostas

1

Resposta separada porque esta é, essencialmente, uma solução diferente

Então, aqui está uma versão cmd / batch.

@echo off
type NUL>output.txt
for /f "tokens=1,3 delims=, skip=1" %%a in (input.txt) do (
    if "%%b"=="" goto :eof
    findstr "^%%b$" output.txt > NUL
    if ERRORLEVEL 1 echo %%b>>output.txt
)

Ele cria o arquivo output.txt e, em seguida, lê o arquivo input.txt usando for e , como um delimitador. A primeira linha é pulada.

O primeiro token ( tokens=1,3 ) precisava ser lido para interrompê-lo na linha some message , já que ele ignoraria a linha e continuaria se o token solicitado ( tokens=3 ) não existisse - e nunca execute o if . %%a é o primeiro token solicitado ( 1 ), %%b é o segundo ( 3 ).

a71,a72,a73,a74
a71,a72,keyC,a74
some message
a71,a72,keyD,a74

keyD não será lido, pois ele pára na linha anterior (não possui um terceiro token). No entanto, a73 será contado.

Isso usa findstr no arquivo de saída para verificar se a chave já está lá - não é eficiente, mas funciona. O RegEx é usado para garantir que corresponda à linha inteira; se uma chave estiver contida inteiramente dentro da outra chave, ela não corresponderá (ou seja, keyA não corresponderá a key ). A saída é canalizada para NUL para manter as coisas quietas.

E se a chave não estiver no arquivo de saída, ela será anexada.

    
por 24.10.2012 / 13:01
1

Você pode usar o PowerShell, que vem com o Windows Vista ou posterior:

$keys = @( );
Import-Csv input.txt | ForEach-Object { 
    if (!$_.head3) {
        $keys | Out-File output.txt;
        break;
    } else {
        if (!($keys -contains $_.head3)) {
            $keys += $_.head3;
        }
    }
}

Isso pode ser lento em grandes quantidades de dados, pois está usando uma matriz ( $keys ) para manter e verificar chaves exclusivas. Um método alternativo é escrever tudo em um arquivo de texto, classificá-lo e executá-lo em Get-Unique . Outra alternativa é usar um hashtable (não ajudaria com o uso da memória, mas seria mais rápido do que verificar se existe algo em um array).

Isso usa Import-Csv , que terá a primeira linha como os títulos. Em seguida, ele passa uma matriz de objetos (linhas) para ForEach-Object . $_ é uma variável que faz referência a cada objeto (linha). .head3 é a propriedade com o nome head3 , conforme definido em seus dados de exemplo como a coluna que contém as chaves. Ele verifica se existe um valor para essa coluna nessa linha; se não, sai para um arquivo e sai como por seu pseudocódigo. Observe que os valores não chave podem ser aceitos. Se você precisar de regras mais rigorosas para o que é uma chave, você pode verificar o comprimento ou fazer alguma correspondência de padrões RegEx, etc.

a71,a72,a73,a74
a71,a72,keyC,a74
some message
a71,a72,keyD,a74

Atualmente, a73 conta como uma chave (está na terceira coluna, head3 ). O programa terminará em some message , já que não possui uma terceira coluna e não lerá keyD .

Se a linha tiver uma coluna-chave, ela verificará se a chave já existe na matriz e, se não, a adiciona. Observe que -contains não faz distinção entre maiúsculas e minúsculas. Se isso for um problema, pode ser alterado.

Então, você provavelmente terá que substituir input.txt output.txt e head3 pelos nomes corretos. Essa foi a solução mais simples que não modifica a ordem dos dados, embora os mais rápidos sejam possíveis, se necessário.

    
por 24.10.2012 / 12:44
0

No Bash (você pode usar o Cygwin se estiver no Windows) isso é fácil:

1.) substituir por nova linha (\ n)

sed -i 's/,/\n/g' superuser.txt

Antes de você:

head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74

Agora você tem:

head1
head2
head3
head4
head5
head6 a11
a12
keyA
a14
a15
a16 a21
a22
keyB
a24
a25 a31
a32
keyC
a34 a41
a42
keyB
a44
a44 a51
a52
keyA
a54
a55
a56 a61
a62
keyA
a64
a65
a66 a71
a72
keyC
a74

2.) Procure por "chave", classifique os resultados e elimine duplicatas

grep -F key superuser.txt | sort | uniq

Dá a você:

keyA
keyB
keyC
    
por 24.10.2012 / 11:21