Ayrı satırları tırnak içine alınmış girişlerle virgülle ayrılmış bir listeye dönüştürme


15

Aşağıdaki verileri (Rmarkdown dosyasından ayrıştırılmış R paketlerinin bir listesi) var, yüklemek için R'ye iletebileceğim bir listeye dönüştürmek istiyorum:

d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr

Listeyi formun bir listesine dönüştürmek istiyorum:

'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'

Şu anda ham dosyadan yukarıdaki listeye giden bir bash boru hattı var:

grep 'library(' Presentation.Rmd \
| grep -v '#' \
| cut -f2 -d\( \
| tr -d ')'  \
| sort | uniq

Yeni satırları virgülle ayrılmış listeye dönüştürmek için bir adım eklemek istiyorum. Eklemeyi denedim tr '\n' '","', hangisi başarısız. Ayrıca, aynı zamanda başarısız aşağıdaki yığın taşması cevapları bir dizi denedim:

Bu library(stringr)))phics)sonuç olarak ortaya çıkar.

Bu ,%sonuç olarak ortaya çıkar.

Bu cevap ( -ibayrak kaldırılmış halde), girişle aynı çıktıyı üretir.


Sınırlayıcıların virgül alanı olması gerekir mi, yoksa yalnızca virgül kabul edilebilir mi?
29'de kaynakçı

Ya iyi, ama ya dize çevreleyen bir alıntı karakter gerek, ya 'da ".
fbt


Giriş verilerinin ve onu işleyen betiğin tamamen uyumsuz olduğunu ilk fark eden ben miyim? Çıktı olmayacak.
ctrl-alt-delor

Listelediğim komut dosyası girdi verilerini nasıl oluşturduğum. Birisi istedi. Gerçek girdi verileri gibi bir şey olur bu . Github'ın yeni satırları kaldırmak için biçimlendirmeyi değiştirdiğini unutmayın.
fbt

Yanıtlar:


19

Sed ile tırnak ekleyebilir ve daha sonra çizgileri macunla birleştirebilirsiniz , örneğin:

sed 's/^\|$/"/g'|paste -sd, -

GNU coreutils tabanlı bir sistem (yani Linux) çalıştırıyorsanız, sondaki işareti atlayabilirsiniz '-'.

Veri girdiğinizde DOS stili satır sonları varsa (@phk'nin önerdiği gibi), komutu aşağıdaki gibi değiştirebilirsiniz:

sed 's/\r//;s/^\|$/"/g'|paste -sd, -

1
MacOS'ta (ve belki de diğerlerinde), girdinin bir dosya yerine stdin'den olduğunu gösteren bir tire eklemeniz gerekir:sed 's/^\|$/"/g'|paste -sd, -
cherdt

Doğru, "coreutils" macunun her iki formu da kabul eder, ancak "-" daha POSIX'tir. Teşekkür !
zeplin

2
Ya da sedyalnız başına:sed 's/.*/"&"/;:l;N;s/\n\(.*\)$/, "\1"/;tl'
Dijital Travma

1
@fbt Cevabımın sonuna eklediğim not burada da geçerli.
phk

1
@DigitalTrauma - gerçekten iyi bir fikir değil; bu çok yavaş olurdu (büyük dosyalarla bile asılabilir) - Q hakkındaki yorumumdaki QI'nin cevaplarına bakın; havalı şey pasteyalnız kullanmaktır ;)
don_crissti

8
Kullanma awk:
awk 'BEGIN { ORS="" } { print p"'"'"'"$0"'"'"'"; p=", " } END { print "\n" }' /path/to/list
Daha az kabuk kaçışına ve dolayısıyla daha okunabilirliğe sahip alternatif:
awk 'BEGIN { ORS="" } { print p"\047"$0"\047"; p=", " } END { print "\n" }' /path/to/list
Çıktı:
'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'
Açıklama:

awkTüm kaçması olmadan senaryo kendisidir BEGIN { ORS="" } { print p"'"$0"'"; p=", " } END { print "\n" }. İlk girişi yazdırdıktan sonra değişken payarlanır (bundan önce boş bir dize gibi). Bu değişkenle pher giriş (veya awk-speak: record ) ön ekine eklenir ve ek olarak etrafında tek tırnak işareti ile yazdırılır. awkÇıkış kayıt ayırıcı değişken ORSen boş olduğu ayarlanır böylece (önek sizin için yapıyor beri) gerekli değildir BEGINing. Oh ve dosyamızı ENDbir satırsonu ile yapabiliriz (örneğin, daha fazla metin işleme aracıyla çalışır); buna ihtiyaç duyulmadığı takdirde ENDve ondan sonraki her şey (tek tırnak içinde) kaldırılabilir.

Not

Windows / DOS stili satır sonlarınız ( \r\n) varsa, bunları önce UNIX stiline ( \n) dönüştürmeniz gerekir . Bunu yapmak tr -d '\015'için boru hattınızın başına koyabilirsiniz :

tr -d '\015' < /path/to/input.list | awk […] > /path/to/output

( \rDosyanızda s için herhangi bir kullanımınız olmadığı varsayılarak . Burada çok güvenli bir varsayım.)

Alternatif olarak, dos2unix /path/to/input.listdosyayı yerinde dönüştürmek için bir kez çalıştırın .


Bu komutu çalıştırdığımda ', 'stringr23aphicsçıktı olarak alıyorum .
fbt

@fbt Son notuma bakın.
phk

2
print p"'"'"'"$0"'"'"'"; p=", "- kutsal alıntılar, Batman!
wchargin

Biliyorum, doğru‽ :) Birçok kabukta baskının p"'\''"$0"'\''";da işe yarayacağını (ancak POSIXy değil) ya da alternatif olarak bash's tırnak dizelerini ( $'') kullanarak bile olsa print p"\'"$0"\'";(diğer ters eğik çizgileri iki katına çıkarmayı gerektirebilirdi ) bahsetmeyi düşündüm. awkkarakterini kullanan diğer yöntem zaten kaçar.
phk

Vay canına, bunu çözdüğüne inanamıyorum. Teşekkür ederim.
fbt

6

As don_crissti en bağlantılı cevabı @ gösterileri, inanılmaz derecede hızlı üzerinde yapıştırma seçeneği sınırları - Linux çekirdeğin boru Demin denedim olmasaydı inanırdım daha etkilidir. Dikkat çekici bir şekilde, virgül + boşluk yerine liste öğelerinizi ayıran tek bir virgülten memnunsanız, bir yapıştırma hattı

(paste -d\' /dev/null - /dev/null | paste -sd, -) <input

makul bir flexprogramdan bile daha hızlıdır (!)

%option 8bit main fast
%%
.*  { printf("'%s'",yytext); }
\n/(.|\n) { printf(", "); }

Ancak, sadece iyi bir performans kabul edilebilirse (ve bir stres testi yapmıyorsanız, herhangi bir sabit faktör farkını ölçemezsiniz, hepsi anındadır) ve hem ayırıcılarınızla hem de makul olanla esneklik istiyorsanız -liner-y-lik,

sed "s/.*/'&'/;H;1h;"'$!d;x;s/\n/, /g'

biletiniz. Evet, hat gürültüsüne benziyor, ancak H;1h;$!d;xdeyim her şeyi karıştırmanın doğru yoludur, bir kez her şeyin okunmasının kolaylaştığını s/.*/'&'/anladıktan sonra, bir slurp ve a gelir s/\n/, /g.


düzenleme: saçma sınır, diğer her şeyi yenmek için esnek almak oldukça kolaydır, sadece stdio yerleşik multithread / signalhandler senkronizasyon gerek yok söyle:

%option 8bit main fast
%%
.+  { putchar_unlocked('\'');
      fwrite_unlocked(yytext,yyleng,1,stdout);
      putchar_unlocked('\''); }
\n/(.|\n) { fwrite_unlocked(", ",2,1,stdout); }

ve stres altında, kendileri her şeyden en az 5 kat daha hızlı olan macun boru hatlarından 2-3 kat daha hızlı.


1
(paste -d\ \'\' /dev/null /dev/null - /dev/null | paste -sd, -) <infile | cut -c2-belirttiğiniz gibi aynı hızda virgül + boşluk @ yapar, ayırıcı olarak süslü bir dizeye ihtiyacınız varsa gerçekten esnek değil
don_crissti

Bu flexşeyler oldukça lanet güzel adam ... bu ilk kez birisinin flexbu sitede kod gönderdiğini görüyorum ... büyük upvote! Lütfen daha fazla şey yayınlayın.
don_crissti

@don_crissti Teşekkürler! Ben iyi fırsatlar, sed / awk / whatnot sadece kolaylık değeri için genellikle daha iyi seçenekler arayacağım ama genellikle de oldukça kolay esnek bir cevap var.
jthill

4

Perl

Python tek astarlı:

$ python -c "import sys; print ','.join([repr(l.strip()) for l in sys.stdin])" < input.txt                               
'd3heatmap','data.table','ggplot2','htmltools','htmlwidgets','metricsgraphics','networkD3','plotly','reshape2','scales','stringr'

Basit bir şekilde çalışır - shell'in <operatörünü kullanarak input.txt dosyasını stdin'e yönlendiririz , her satırı .strip()yeni satırları kaldırarak ve repr()her satırın alıntılanmış bir temsilini oluşturarak bir listede okuruz . Liste daha sonra ayırıcı olarak .join()işlev aracılığıyla büyük bir dizeye eklenir,

Alternatif olarak, +alıntıları her soyulmuş satıra birleştirmek için kullanabiliriz .

 python -c "import sys;sq='\'';print ','.join([sq+l.strip()+sq for l in sys.stdin])" < input.txt

Perl

Esasen daha önce olduğu gibi aynı fikir: tüm satırları oku, sondaki satırı kaldır, tek tırnak içine al, her şeyi array @cvs'e doldur ve virgüllerle birleştirilmiş dizi değerlerini yazdır.

$ perl -ne 'chomp; $sq = "\047" ; push @cvs,"$sq$_$sq";END{ print join(",",@cvs)   }'  input.txt                        

'D3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'ölçek', 'stringr'


IIRC, pitonlar joinbir yineleyici alabilmelidir, bu nedenle stdin döngüsünü bir listeye gerçekleştirmeye gerek yoktur
iruvar

@iruvar Evet, OP'nin istenen çıktısına bakmak dışında - her bir kelimenin alıntılanmasını istiyorlar ve çıktının bir satır olduğundan emin olmak için son satırları kaldırmamız gerekiyor. Liste anlamadan bunu nasıl yapacağınız hakkında bir fikriniz var mı?
Sergiy Kolodyazhnyy

3

Dosya metninde veri olduğunuzu varsayarak, aşağıdakilerin iyi olması gerektiğini düşünüyorum

d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr

İkamesi soğuk olan dizileri kullanalım:

#!/bin/bash
input=( $(cat text) ) 
output=( $(
for i in ${input[@]}
        do
        echo -ne "'$i',"
done
) )
output=${output:0:-1}
echo ${output//,/, }

Komut dosyasının çıktısı aşağıdaki gibi olmalıdır:

'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'

Aradığın şey olduğuna inanıyorum?


1
Güzel çözüm. Ancak OP açıkça istemediğinde bashve birisinin onu kullanabileceğini varsaymak güvenli olsa da (sonuçta en çok kullanılan AFAIK kabuktur) hala kabul edilmemelidir. Ayrıca, alıntıda çok daha iyi bir iş yapabileceğiniz parçalar var (çift tırnak işaretleri koyarak). Örneğin, paket adlarının içlerinde boşluk olması olası olmasa da, değişkenleri alıntılamak yerine hala iyi bir kural olsa da, shellcheck.net'i çalıştırmak ve notları ve açıklamaları görmek isteyebilirsiniz .
phk

2

Genellikle çok benzer bir senaryo var: Excel'den bir sütun kopyalayın ve içeriği (gibi bir SQL sorgusunda daha sonra kullanmak için) virgülle ayrılmış bir listeye dönüştürmek istiyorum ... WHERE col_name IN <comma-separated-list-here>.

Bu benim .bashrc benim var:

function lbl {
    TMPFILE=$(mktemp)
    cat $1 > $TMPFILE
    dos2unix $TMPFILE
    (echo "("; cat $TMPFILE; echo ")") | tr '\n' ',' | sed -e 's/(,/(/' -e 's/,)/)/' -e 's/),/)/'
    rm $TMPFILE
}

Daha sonra lblgiriş için bekleyen cmd satırında ("satır satır") çalıştırın , panodan içeriği yapıştırın, tuşuna basın <C-D>ve işlev çevrili girişi döndürür (). Bu şöyle görünür:

$ lbl
1
2
3
dos2unix: converting file /tmp/tmp.OGM6UahLTE to Unix format ...
(1,2,3)

(Dos2unix'i neden buraya koyduğumu hatırlamıyorum, muhtemelen şirketimin kurulumunda sık sık soruna neden oluyor.)


1

Sed Bazı sürümleri biraz farklı hareket, ama benim mac, sed "uniq" dışında her şeyi işleyebilir:

sed -n -e '
# Skip commented library lines
/#/b
# Handle library lines
/library(/{
    # Replace line with just quoted filename and comma
    # Extra quoting is due to command-line use of a quote
    s/library(\([^)]*\))/'\''\1'\'', /
    # Exchange with hold, append new entry, remove the new-line
    x; G; s/\n//
    ${
        # If last line, remove trailing comma, print, quit
        s/, $//; p; b
    }
    # Save into hold
    x
}
${
    # Last line not library
    # Exchange with hold, remove trailing comma, print
    x; s/, $//; p
}
'

Ne yazık ki benzersiz kısmı düzeltmek için aşağıdaki gibi bir şey yapmalısınız:

grep library Presentation.md | sort -u | sed -n -e '...'

--Paul


2
Unix.stackexchange'e hoş geldiniz! Tura katılmanızı tavsiye ederim .
Stephen Rauch

0

R paketlerini yüklemek için R paketlerinin düz metin listesini kullanmak hiç kimsenin bu listeyi doğrudan R'de kullanarak bir çözüm önermediği, ancak bash, perl, python, awk, sed veya liste. Bu hiç gerekli değildir ve üstelik R'deki dönüştürülmüş listenin nasıl girdiğini ve kullanılacağını çözmez.

Düz metin dosyasını (adı geçen packages.txt), doğrudan kullanılabilen bir vektör olarak ayıklayabileceğiniz tek değişkenli bir veri çerçevesi olarak yükleyebilirsiniz install.packages. Yani, onu kullanılabilir bir R nesnesine dönüştürün ve bu listeyi yükleyin:

df <- read.delim("packages.txt", header=F, strip.white=T, stringsAsFactors=F)
install.packages(df$V1)

Veya harici bir dosya olmadan:

packages <-" 
d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr
"
df <- read.delim(textConnection(packages), 
header=F, strip.white=T, stringsAsFactors=F)
install.packages(df$V1)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.