'\ r' não funciona como `lineterminator` no Python` csv.writer () `

Oct 17 2020

Estou trabalhando no Windows. Eu tenho um arquivo Python para criar um novo arquivo CSV e vejo isso usando o bloco de notas (mesmo através do Ms Excel).

import csv
data=[['fruit','quantity'],['apple',5],['banana',7],['mango',8]]
with open('d:\lineter.csv','w') as l:
    w=csv.writer(l,delimiter='|',lineterminator='\r')
    w.writerows(data)

O arquivo resultante no bloco de notas:

fruit|quantityapple|5banana|7mango|8

Minha dúvida aqui é se o retorno de carro \rfunciona ou não ??? Ele funciona como lineterminator=''no bloco de notas . Mas no Excel, funciona como '\ n'

A saída não parece implementar o retorno de carro. Quando eu uso o lineterminator como:

w=csv.writer(l,delimiter='|',lineterminator='*\r*\n')

A saída no bloco de notas é:

fruit|quantity**
apple|5**
banana|7**
mango|8**

Isso também é evidente aqui.

Alguém pode me dizer como '\ r' funciona no lineterminator no escritor ()? Ou há alguma outra coisa acontecendo lá?

Respostas

7 GabrielStaples Oct 19 2020 at 03:25

A resposta mais curta:

Quando usar Carriage Return (CR, \r) vs Line Feed (LF, \n) vs ambos (CRLF, \r\n) para fazer uma nova linha aparecer em um editor de texto no Windows, Mac e Linux:

Alguém pode me dizer como '\ r' funciona no lineterminator no escritor ()?

Funciona bem em csv.writer(). Este não é realmente um problema de Python, CSV ou escritor. Esta é uma diferença histórica do sistema operacional (na verdade, é mais preciso afirmar que é uma diferença específica do programa ) que remonta aos anos 1960 ou mais.

Ou há alguma outra coisa acontecendo lá?

Sim, é esse.

Sua versão do Notepad não reconhece um Carriage Return ( \r) como um caractere usado para exibir novas linhas e, portanto, não o exibirá como tal no Notepad. Outros editores de texto, como o Sublime Text 3 , provavelmente o fariam, mesmo no Windows.

Até cerca do ano 2018 ou assim, o Windows e o Bloco de notas exigiam um Retorno de carro + Alimentação de linha ( \r\n) juntos para exibir uma nova linha. Compare isso com Mac e Linux, que exigem apenas \n.

A solução é usar \r\npara uma nova linha no Windows, e \nsozinho para uma nova linha no Mac ou Linux. Você também pode tentar um editor de texto diferente, como Sublime Text, ao visualizar ou editar arquivos de texto , ou atualizar sua versão do Windows ou do Bloco de notas, se possível, já que em algum lugar por volta do ano de 2018 o Bloco de Notas do Windows começou a aceitar \rsozinho como um antigo Nova linha de char.

(do comentário do OP sob esta resposta):

Então, por que dar '\ r \ n' ???

Quando um programador escreve um programa, o programador pode fazer o programa fazer tudo o que o programador deseja que o programa faça. Quando os programadores do Windows criaram o Windows e o Bloco de notas, eles decidiram fazer o programa não fazer nada se tivesse um \r, nada se tivesse um \n, e fazer uma nova linha se tivesse um \r\n junto . É simples assim. O programa está fazendo exatamente o que os programadores mandaram, porque decidiram que era assim que queriam que o programa funcionasse. Portanto, se você deseja uma nova linha na versão mais antiga (pré-2018) do Bloco de notas no Windows, deve fazer o que os programadores exigem que você faça para obtê-la. \r\né isso.

Isso remonta aos dias das teletipoas (leia as seções "História" e "Representação" aqui) e esta página sobre "teleimpressoras" / "teletipoascritas" / "teletipo ou máquinas TTY" também:

Uma máquina de escrever ou impressora eletromecânica pode imprimir caracteres no papel e executar operações como mover o carro de volta para a margem esquerda da mesma linha ( retorno do carro ), avançar para a mesma coluna da próxima linha ( alimentação de linha ) e assim por diante .
( fonte ; ênfase adicionada)

O botão de retorno mecânico do carro em um teletipo ( \ragora em um computador) significava: "retornar o carro (cabeça de impressão) para o início da linha" (significando: o lado esquerdo da página), e o mecanismo mecânico de alimentação de linha ligado um teletipo ( \nagora em um computador) significava: "enrole o papel uma linha para que possamos digitar na próxima linha." Sem a \nação mecânica de avanço de linha ( ), o retorno do carro ( \r) sozinho moveria o cabeçote de impressão mecânico para a extrema esquerda da página e faria com que você digitasse de volta em cima das palavras já digitadas! E sem a ação mecânica de retorno de carro ( \rem um computador), a ação mecânica de avanço de linha ( \n) por si só faria com que você digite apenas a última coluna na extrema direita em cada nova linha na página, nunca capaz de retornar o cabeçote de impressão para o lado esquerdo da página novamente! Em um teletipo de escrever eletromecânico, ambos tiveram que ser usados: o retorno do carro traria o cabeçote de impressão de volta para o lado esquerdo da página, e a ação de avanço de linha moveria o cabeçote de impressão para a próxima linha . Portanto, presumivelmente, os programadores do Windows sentiram que era lógico manter viva essa tradição e decidiram exigir AMBOS a \r\n juntos para criar uma nova linha em um computador, já que era assim que deveria ser feito tradicionalmente em uma teletipoeira eletromecânica .

Leia abaixo para obter detalhes.

Detalhes:

Tenho algumas ideias sobre o que está acontecendo, mas vamos dar uma olhada. Acredito que temos 2 perguntas para responder:

  1. O está \rrealmente sendo armazenado no arquivo?
  2. O bloco de notas está realmente mostrando o \re, se não, por que não?

Portanto, para o nº 1. Vamos testá-lo no Linux Ubuntu 20.04:

Este programa:

#!/usr/bin/python3

import csv
data=[['fruit','quantity'],['apple',5],['banana',7],['mango',8]]
with open('d:\lineter.csv','w') as l:
    w=csv.writer(l,delimiter='|',lineterminator='\r')
    w.writerows(data)

produz este arquivo: d: \ lineter.csv . Se eu abrir no editor de texto Sublime Text 3, vejo:

fruit|quantity
apple|5
banana|7
mango|8

Por enquanto, tudo bem. Vejamos os caracteres com hexdumpa linha de comando:

hexdump -cmostra os \rchars, com certeza!

$ hexdump -c d\:\\lineter.csv 
0000000   f   r   u   i   t   |   q   u   a   n   t   i   t   y  \r   a
0000010   p   p   l   e   |   5  \r   b   a   n   a   n   a   |   7  \r
0000020   m   a   n   g   o   |   8  \r                                
0000028

Você também pode usar hexdump -Cpara mostrar os caracteres em hexadecimal, e novamente, vejo o \rno arquivo como um 0dcaractere hexadecimal , o que é correto.

Ok, então eu inicializo o Windows 10 Professional na minha máquina virtual Virtual Box no Linux, e abro o mesmo arquivo no Notepad, e .... funciona também! Veja a imagem:

Mas, observe a parte que circulei que diz "Macintosh (CR)". Estou executando a versão mais recente do Windows 10 Professional. Aposto que você está usando uma versão antiga do Bloco de notas que não tem essa correção, e a sua não vai dizer isso aqui. Isso ocorre porque por 33 anos o Bloco de Notas não manipulou o Retorno de Carro ou \r, como um final de linha válido, então não o exibiu como tal. Veja aqui: Windows Notepad corrigido após 33 anos: Agora ele finalmente lida com Unix e terminações de linha do Mac OS .

Devido às diferenças históricas que datam de teletipoaspiradores e código morse (leia as seções "História" e "Representação" aqui), sistemas diferentes decidiram fazer seus editores de texto tratarem os finais de linha de maneiras diferentes. Do artigo acima (ênfase adicionada):

O bloco de notas reconhecia anteriormente apenas os caracteres de fim de linha (EOL) do Windows, especificamente Retorno de carro (CR, \ r, 0x0d) e Avanço de linha (LF, \ n, 0x0a) juntos .

Para o Mac OS da velha escola, o caractere EOL é apenas Retorno de carro (CR, \ r, 0x0d) e para Linux / Unix é apenas Alimentação de linha (LF, \ n, 0x0a) . O macOS moderno, desde o Mac OS X, segue a convenção do Unix.

Portanto, o que temos aqui é o seguinte exibido como uma nova linha em um editor de texto:

  1. Mac antigo:\r somente CR ( )
  2. Bloco de notas do Windows até ~ 2018: CR e LF juntos ( \r\n)
  3. Linux: LF ( \n) apenas
  4. Mac moderno:\n apenas LF ( )
  5. Bloco de notas moderno do Windows (ano ~ 2018 e posteriores): qualquer um dos cenários acima.

Então, para Windows , continue usando sempre\r\n para uma nova linha, e para Mac ou Linux , apenas use sempre \npara uma nova linha, a menos que você esteja tentando garantir a compatibilidade com o Windows da velha escola (ou seja: pré-2019 :)) de seus arquivos, caso em que você deve usar \r\npara novas linhas também.


Observe, para Sublime Text 3, eu apenas pesquisei as preferências em Preferências -> Configurações e encontrei esta configuração:

    // Determines what character(s) are used to terminate each line in new files.
    // Valid values are 'system' (whatever the OS uses), 'windows' (CRLF) and
    // 'unix' (LF only).
    "default_line_ending": "system",

Portanto, para usar a convenção para qualquer sistema operacional em que você esteja executando o Sublime Text, o padrão é "sistema". Para forçar o término de linha de 'janelas' (CRLF) ao editar e salvar arquivos em Texto Sublime, use isto:

"default_line_ending": "windows",

E para forçar as configurações de finalização de linha somente LF do Unix (Mac e Linux), use isto:

"default_line_ending": "unix",

No editor do Bloco de notas, não consigo encontrar essas configurações para definir. É um editor simples, atendendo por 33 anos apenas às terminações de linha do Windows.

Leitura Adicional:

  1. https://en.wikipedia.org/wiki/Teleprinter
  2. https://en.wikipedia.org/wiki/Newline#History
  3. É uma nova linha = \ n OU \ r \ n?
  4. Por que o Windows usa CR LF?
DavidCullen Oct 17 2020 at 00:45

Eu adicionei o código para exibir os valores no arquivo CSV em hexadecimal:

import csv
data=[['fruit','quantity'],['apple',5],['banana',7],['mango',8]]
with open('lineter.csv','w') as l:
    w=csv.writer(l,delimiter='|',lineterminator='\r')
    w.writerows(data)

with open('lineter.csv', 'rb') as l:
    counter = 0
    while True:
        char = l.read(1)
        if not len(char):
            break
        print("%02X " % ord(char), end='')
        counter += 1
        if counter % 8 == 0:
            print("")

Resultado

66 72 75 69 74 7C 71 75 
61 6E 74 69 74 79 0D 61 
70 70 6C 65 7C 35 0D 62 
61 6E 61 6E 61 7C 37 0D 
6D 61 6E 67 6F 7C 38 0D 

Como você pode ver, o \rpersonagem está lá ( 0D).

Se modificarmos o código a ser usado '*\r*', obteremos o resultado esperado:

Resultado

66 72 75 69 74 7C 71 75 
61 6E 74 69 74 79 2A 0D 
2A 61 70 70 6C 65 7C 35 
2A 0D 2A 62 61 6E 61 6E 
61 7C 37 2A 0D 2A 6D 61 
6E 67 6F 7C 38 2A 0D 2A 

A sequência 2A 0D 2Aé *\r*.