BATCH Script - como faço para contar ocorrências de COMMA em um arquivo CSV ou TXT?

0

Eu tenho muitos arquivos CSV para processar diariamente. Eles têm um formulário constante com 19 COMMAS para aparecer em todos os arquivos. No arquivo, há uma mistura de strings, timestamps, inteiros e dígitos flutuantes. O arquivo sempre termina com o conjunto CR-LF.

Cada arquivo tem apenas uma linha desse texto, que fornece um conjunto de informações que são processadas posteriormente.

O problema parece que, de tempos em tempos (uma vez a cada 1000 arquivos), o dispositivo responsável pela geração desse arquivo cria o arquivo INCOMPLETE. Algumas informações estão faltando.

Eu preciso separar esses arquivos de todos os arquivos bons antes de processá-los ainda mais.

Depois de passar um tempo considerável tentando descobrir a maneira mais robusta de resolver isso, cheguei à conclusão de que, como o arquivo está incompleto, falta algum COMMAS.

Portanto, quero contar a quantidade de COMMAS que aparece no arquivo CSV. O arquivo correto deve ter 19 vírgulas, qualquer arquivo problemático que eu tenha descoberto no último semestre terá menos que isso. Eles também têm falta de CR-LF no final da linha. Eles simplesmente terminam com vírgula depois de algum valor e é isso.

Exemplo de um bom arquivo CSV:

STRING1,STRING2,2017-01-20 17:34:08,53.808536,-7.789231,19.5,3,0,STRING3,2017-01-20 17:34:19,2,0,7.9,2,0,1,0,0,0,0

Exemplo de arquivo CSV incorreto:

STRING1,STRING3,2017-01-12 10:11:09,53.779093,-7.494274,

Minha pergunta é: Como posso contar a quantidade de COMMAS em um único arquivo CSV, e se esse valor não corresponder ao número definido para executar uma determinada operação (como mover esse arquivo incorreto na pasta ERRORS, que eu poderia lidar com mais tarde). Se o arquivo tiver a quantidade correta de COMMAS, apenas deixe. Então, outras palavras que eu preciso para mover arquivos CSV formatados incorretamente para uma pasta ERRORS e deixar os arquivos CSV corretamente formatados como estavam.

FYI: os arquivos CSV sempre têm apenas uma linha de dados.

Eu experimentei certas soluções, que estão tentando localizar e contar instâncias de certas cadeias de caracteres em um arquivo TXT, mas isso não me leva a lugar nenhum. Talvez porque minha string seja apenas um sinal de COMMA ... Eu não sei.

Eu gostaria muito que você ajudasse nesse assunto.

    
por Piotruncio 23.01.2017 / 13:05

4 respostas

1

Como faço para contar ocorrências de , em um arquivo CSV?

Use o seguinte arquivo em lotes (CountCommas.cmd):

@echo off
setlocal EnableDelayedExpansion
set _comma=,
for /f "usebackq" %%a in ('dir /b /s *.csv')  do (
  set _file=%%a
  set count=0
  for /f "usebackq tokens=*" %%b in ('type !_file!') do (
    set _line=%%b
    call :count
  )
)
goto :done
:count
    if !_line:~0^,1! equ !_comma! (
      set /a count+=1
      )
    if "!_line:~1!" neq "" (
      set _line=!_line:~1!
      goto :count
      )
    echo file !_file! contains !count! commas
    if !count! neq 19 (
      echo error
      rem handle error here
      )
    )
:done
endlocal

Notas:

  • Substitua rem handle error here pelo seu código de tratamento de erros

Exemplo de uso:

> type bad.csv
STRING1,STRING3,2017-01-12 10:11:09,53.779093,-7.494274,
> type good.csv
STRING1,STRING2,2017-01-20 17:34:08,53.808536,-7.789231,19.5,3,0,STRING3,2017-01-20 17:34:19,2,0,7.9,2,0,1,0,0,0,0
> CountCommas
file F:\test\bad.csv contains 5 commas
error
file F:\test\good.csv contains 19 commas

Leitura Adicional

  • Um índice A-Z da linha de comando do Windows CMD - Uma excelente referência para todas as coisas relacionadas à linha do Windows cmd.
  • dir - Exibe uma lista de arquivos e subpastas.
  • para / f - Comando Loop contra os resultados de outro comando.
  • if - Realize condicionalmente um comando.
  • definir - Exibir, definir ou remover variáveis de ambiente do CMD. As alterações feitas com o SET permanecerão apenas pela duração da sessão atual do CMD.
  • variáveis - Extrai parte de uma variável (substring).
por 23.01.2017 / 15:59
2

A expressão regular FINDSTR $ corresponde apenas à posição antes de um CR. Portanto, se seus arquivos inválidos não tiverem o CR-LF, você poderá usar o seguinte liner para mover todos os arquivos csv com problemas para a pasta de erros.

for /f "eol=: delims=" %F in ('findstr /vm $ *.csv') do @move /y "%F" error >nul

Você deve dobrar as porcentagens se colocar o comando dentro de um script em lote.

@echo off
for /f "eol=: delims=" %%F in ('findstr /vm $ *.csv') do move /y "%%F" error >nul

Se preferir, você pode usar uma expressão regular mais complicada para procurar linhas que não contenham 19 vírgulas:

@echo off
for /f "eol=: delims=" %%F in (
  'findstr /vm ".*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*," *.csv'
) do move /y "%%F" error >null

Mas simplesmente contar vírgulas pode não ser confiável, porque os valores citados também podem conter vírgulas, como LotPings aponta em sua resposta.

    
por 25.01.2017 / 06:10
1

A pergunta deve ser Como posso garantir que o arquivo csv tenha 20 colunas / campos

Presumir que as strings no arquivo não são citadas e não contêm vírgulas que esse lote fará:

@Echo off&SetLocal EnableExtensions EnableDelayedExpansion
CD /d "X:\path\to\csv-folder"
Set Cnt=0
For %%A in (*.csv) Do Set File="%%A"&Set /P CSV=<%%A&Call :Count "!CSV:,=","!"
Goto :Eof
:Count
If "%~1" Neq "" Shift & Set /A Cnt+=1 & Goto :Count
If %Cnt% Neq 20 Echo %File% has %Cnt% Columns
Set "CSV="
Set Cnt=0

O lote inclui a linha entre aspas duplas e também substitui cada vírgula individual , por "," para que todas as colunas sejam citadas. Tudo isso passou para a sub-rotina :Count onde os argumentos são contados e deslocados até não mais presentes. Se a contagem for diferente de 20, um eco emitirá a mensagem de erro. Isso pode ser substituído por um comando de movimento.

    
por 23.01.2017 / 17:11
0

Uma maneira fácil com o lote para contar caracteres de string em um arquivo

Você pode usar um script em lote e inserir a lógica simples para criar um script dinâmico do PowerShell para fazer a contagem dos caracteres , commas, definir a contagem para uma variável e usar essa variável de acordo com o restante as operações do processo na lógica do script em lote.

O script PS não precisa ser criado dinamicamente e você pode usar um script PS estático. Você poderia passar o caminho completo do Script PS como o primeiro argumento a usar para o seu script em lote.

Isto é fácil ... pronto ... próximo !!

Exemplo de script em lote

ECHO ON

SET file=C:\folder\file.txt

CALL :CreatePSCommaCount
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0 
CD /D "%PowerShellDir%" 
FOR /F "DELIMS=" %%A IN ('Powershell -ExecutionPolicy Bypass -Command "& '%DynPSCommaCount%'"') DO SET "commacount=%%A"

IF NOT %commacount%==19 GOTO EOF
<other batch script logic below here since count is 19 (or whatever you need it to be)>
GOTO EOF

:CreatePSCommaCount
SET DynPSCommaCount=%Temp%\TempCommaCount.ps1
IF EXIST "%DynPSCommaCount%" DEL /Q /F "%DynPSCommaCount%"
ECHO $file  = GC "%file%"                                               >>"%DynPSCommaCount%"
ECHO $Match = Select-String -InputObject $file -Pattern "," -AllMatches >>"%DynPSCommaCount%"
ECHO $Match.Matches.Count                                               >>"%DynPSCommaCount%"
GOTO EOF

Você colocaria uma condição IF simples no script em lote e usaria o move para mover o arquivo se ele corresponder ou não a um número, no entanto, você tem essa lógica no script em lote existente.

Mais recursos

por 23.01.2017 / 15:57