Gerar arquivo .txt com conteúdo específico de um arquivo .json de 3 GB inválido

1

Eu tenho um arquivo chamado users.json, que tem 3 GB, e é inválido json. Então, o que estou tentando fazer é ler o conteúdo de texto do arquivo e pegar as informações de que preciso, que são os nomes de usuário contidos no arquivo, e gravá-las em um arquivo usernames.txt que deve conter 1 nome de usuário por linha, com sem duplicatas.

O formato dos nomes de usuários no json é o seguinte: "username": "someUsername"

Como posso reunir todos os nomes de usuários, colocá-los no arquivo de texto e garantir que não haja duplicatas?

Eu tentei via Node.js e PHP e nada está funcionando de forma eficiente ainda, espero que algo legal possa ser feito usando o bash.

Exemplo de dados contidos no arquivo (provavelmente não ajuda muito, como já mencionei sobre o formato "username":"someUsername" ):

username":"satish_nanded","original_ff_id":"99554"},"100003":{"username":"sweetnamu","original_ff_id":"100003"}},"08fdlhNuZEM1z8q4mQftYUtO7uC3":{"575511":{"username":"lrlgrdnr","original_ff_id":"575511"}},"08fe4Dg7NeOTItq3b9Pi8ORsX5J2":{"59520":{"username":"joneljon","original_ff_id":"59520"}},"08gsZHsbm9Rew4S2IqcbGvD9Fct1":{"724707":{"username":"jacksonc4565","original_ff_id":"724707"}

    
por Dan P. 24.03.2017 / 20:26

2 respostas

2

Você pode usar o comando grep para corresponder aos padrões necessários e sort para filtrar as duplicatas. Se o seu arquivo de entrada for input.json e a saída for usernames.txt :

grep -P -o '(?<="username":")[^"]*' input.json | sort -u > usernames.txt

Quebrando:

  • grep é um utilitário de linha de comando para corresponder expressões regulares em um arquivo. Expressões regulares são uma maneira poderosa de descrever partes do texto que você deseja encontrar
  • -P informa grep para usar "Expressões regulares compatíveis com Perl". Note que a página man do grep descreve isso como "altamente experimental"!
  • -o diz a grep para produzir apenas o texto correspondente. Por padrão, grep normalmente produziria toda a linha sempre que uma correspondência fosse encontrada.
  • '(?<="username":")[^"]*' é a expressão regular em si:
    • Colocamos em aspas simples '....' para impedir que o shell da linha de comando tente interpretar qualquer coisa nele
    • (?<=...) é o que é chamado de asserção lookbehind . Ele diz que queremos corresponder "username":" antes de outra coisa, mas não incluí-lo na saída
    • [^"]* significa "o maior número possível de caracteres que não são " . Pode ser dividido novamente:
    • [..] é uma classe de caracteres. Qualquer caractere colocado entre colchetes é permitido neste momento. A menos que ...
    • ^" Quando você usa um caret ^ como primeiro caractere em uma classe de caracteres, isso significa não nenhum dos seguintes caracteres
    • * significa 0 ou mais do item anterior (que é o total de [^"] neste caso).

Pipar o lote em sort classifica os nomes de usuários em ordem alfabética, o que, com a opção -u , significa "somente itens exclusivos", ou seja, sem duplicatas.

Nota: Tudo isso pressupõe que o padrão que estamos combinando não pode ocorrer em nenhum outro lugar no arquivo (o que parece improvável) ou que o quebrantamento do próprio JSON não fará com que a correspondência falhe (o que pode Não sei ao certo como o seu arquivo está quebrado).

EDITAR: Com grep reclamando regularmente que as linhas eram muito longas e, por algum motivo, sed -e 's/,/,\n/' não estava funcionando, o comando split foi usado para dividir o arquivo em partes mais gerenciáveis.

    
por 24.03.2017 / 22:49
0

Você parece ter registros JSON muito longos que quebram grep -P , eis uma solução alternativa:

grep -o '"username":"[^"]*' users.json \
| cut -d '"' -f 4 \
| uniq \
| sort -u \
> usernames.txt

Aqui, grep extrai os campos "username: value" completos, cut extrai o valor e uniq | sort -u torna os nomes de usuários únicos.

uniq não é necessário. Com um arquivo de 3GB, espero uma lista de milhões de nomes, com muitos duplicados sucessivos. O uniq | aparentemente inútil alivia sort de uma parte de seu trabalho e pode torná-lo mais rápido. Senão, não vai doer.

    
por 25.03.2017 / 00:05