将单独的行转换为带有引号条目的逗号分隔列表

将单独的行转换为带有引号条目的逗号分隔列表

我有以下数据(从 Rmarkdown 文件解析的 R 包列表),我想将其转换为可以传递给 R 进行安装的列表:

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

我想将列表变成以下形式的列表:

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

我目前有一个从原始文件到上面列表的 bash 管道:

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

我想添加一个步骤将新行转换为逗号分隔列表。我尝试添加tr '\n' '","',但失败了。我还尝试了以下一些 Stack Overflow 答案,但也失败了:

这产生了library(stringr)))phics)结果。

这产生了,%结果。

这个答案(-i删除标志)产生与输入相同的输出。

答案1

您可以添加引号sed然后将行与粘贴, 像那样:

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

如果您运行的是基于 GNU coreutils 的系统(即 Linux),则可以省略结尾的'-'.

如果您输入的数据具有 DOS 风格的行结尾(如 @phk 建议),您可以按如下方式修改命令:

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

答案2

使用awk
awk 'BEGIN { ORS="" } { print p"'"'"'"$0"'"'"'"; p=", " } END { print "\n" }' /path/to/list
外壳转义较少,因此更具可读性的替代方案:
awk 'BEGIN { ORS="" } { print p"\047"$0"\047"; p=", " } END { print "\n" }' /path/to/list
输出:
'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'
解释:

awk没有所有转义的脚本本身是BEGIN { ORS="" } { print p"'"$0"'"; p=", " } END { print "\n" }.打印第一个条目后,变量p被设置(在此之前它就像一个空字符串)。使用此变量p每个条目(或用awk-speak:记录) 是前缀,并且另外打印时用单引号括起来。不需要输出记录分隔符变量(因为前缀已经为您完成了),因此在 ing 时将其设置为awk空。哦,我们可能会在文件中添加换行符(例如,这样它可以与其他文本处理工具一起使用);如果不需要,则可以删除其后的部分及其后的所有内容(单引号内)。ORSBEGINENDEND

笔记

如果您有 Windows/DOS 样式的行结尾 ( \r\n),则必须先将它们转换为 UNIX 样式 ( \n)。为此,您可以将其放在tr -d '\015'管道的开头:

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

\r(假设您的文件中没有任何 s 用途。这里是非常安全的假设。)

或者,只需运行dos2unix /path/to/input.list一次即可就地转换文件。

答案3

作为@don_crissti 的链接答案表明,粘贴选项的速度快得令人难以置信——Linux 内核的管道比我现在没有尝试过的更高效。值得注意的是,如果您对用单个逗号分隔列表项而不是逗号+空格感到满意,那么粘贴管道

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

甚至比合理的程序还要快flex(!)

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

但是,如果体面的性能是可以接受的(并且如果您没有运行压力测试,您将无法测量任何常数因子差异,它们都是即时的)并且您希望分离器既具有灵活性又具有合理性-线性度,

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

是你的票。是的,它看起来像线路噪音,但这个H;1h;$!d;x习语是吸收所有内容的正确方法,一旦你认识到整个内容实际上变得很容易阅读,后面就会s/.*/'&'/出现 slurp 和s/\n/, /g.


编辑:近乎荒谬,让 flex 击败其他一切是相当容易的,只需告诉 stdio 你不需要内置的多线程/信号处理程序同步:

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

在压力下,它比粘贴管道快 2-3 倍,而粘贴管道本身比其他管道快至少 5 倍。

答案4

Python

Python 一行:

$ 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'

工作方式很简单 - 我们使用 shell 的<运算符将 input.txt 重定向到 stdin,将每一行读入列表,.strip()删除换行符并repr()创建每行的带引号的表示形式。然后通过函数将列表连接成一个大字符串.join(),并,使用分隔符

或者,我们可以使用+将引号连接到每个剥离的行。

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

珀尔

本质上与以前的想法相同:读取所有行,删除尾随换行符,用单引号引起来,将所有内容填充到数组 @cvs 中,并打印出用逗号连接的数组值。

$ 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','scales','stringr'

相关内容