Perl 将Unix`cal`输出转换为latex表代码:一行程序解决方案?

Perl 将Unix`cal`输出转换为latex表代码:一行程序解决方案?,perl,bash,shell,sed,awk,Perl,Bash,Shell,Sed,Awk,为了实现以下目标,我绞尽脑汁: 使用简短的单行程序(或少数行程序)将Unixcal输出转换为latex表代码 例如cal-h 02 2012 |$magicline应产生 Mo &Tu &We &Th &Fr \\ & & 1 & 2 & 3 \\ 6 & 7 & 8 & 9 &a

为了实现以下目标,我绞尽脑汁:

使用简短的单行程序(或少数行程序)将Unix
cal
输出转换为latex表代码

例如
cal-h 02 2012 |$magicline
应产生

Mo      &Tu     &We     &Th     &Fr     \\
        &       & 1     & 2     & 3     \\
 6      & 7     & 8     & 9     &10     \\
13      &14     &15     &16     &17     \\
20      &21     &22     &23     &24     \\
27      &28     &       &       &       \\
到目前为止,我能想出的唯一合理的解决办法是

cal -h | sed -r -e '1d' -e \
  's/^(..)?(...)?(...)?(...)?(...)?(...)?(...)?$/\2\t\&\3\t\&\4\t\&\5\t\&\6\t\\\\/'
。。。我真的很努力。它的优点是它简单易懂,缺点是它“不灵活”(它无法应付一周8天),而且有点冗长。我正在寻找可供学习的替代解决方案;-)

编辑:找到另一个似乎可以接受的

cal -h | tail -n +2 |
    perl -ne 'chomp;
        $,="\t&";
        $\="\t\\\\\n";
        $line=$_;
        print map {substr($line,$_*3,3)} (1..5)'
编辑:不错的一个:

cal -h | perl \
    -F'(.{1,3})' -ane \
        'BEGIN{$,="\t&";$\="\t\\\\\n"}
            next if $.==1;
            print @F[3,5,7,9,11]'
这将产生:

Mo     &Tu     &We     &Th     &Fr    \\
       &       & 1     & 2     & 3    \\
 6     & 7     & 8     & 9     &10    \\
13     &14     &15     &16     &17    \\
20     &21     &22     &23     &24    \\
27     &28     &29     &       &      \\

您可以轻松地将
\t
替换为所需的空格数

这适用于我的
cal
实现,它使用四个字符列,并具有显示月份和年份的初始标题行

cal | perl -pe "next if $.==1;s/..../$&&/g;s/&$/\\\\/"
看起来您的可能有八个字符的列,并且没有标题行,在这种情况下

cal | perl -pe "s/.{8}/$&&/g;s/&$/\\\\/"

应该做到这一点,但要做好调整的准备。

使用GNU版本的
awk

我的
cal
输出使用英语
LANG

命令:

LANG=en_US cal
输出:

    February 2012   
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29

awk
一行:

LANG=en_US cal | awk '
BEGIN { 
  FIELDWIDTHS = "3 3 3 3 3 3 3"; 
  OFS = "&";
} 
FNR == 1 || $0 ~ /^\s*$/ { next } 
{ 
  for (i=2; i<=6; i++) { 
    printf "%-3s%2s", $i, i < 6 ? OFS : "\\\\";
  } 
  printf "\n";
}'
在OS-X上测试:

cal 02 2012 |grep . |tail +2 |perl -F'/(.{3})/' -ane \
    'chomp(@F=grep $_,@F); $m=$#F if !$m; printf "%s"."\t&%s"x$m."\t\\\\\n", @F;'
其中,
cal
输出有3个字符的列<可以更改代码>{3}以匹配
cal
输出

cal 02 2012|perl -lnE'$.==1||eof||do{$,="\t&";$\="\t\\\\\n";$l=$_;print map{substr($l,$_*3,3)}(1..5)}'
我的最爱:

cal 02 2012|perl -F'(.{1,3})' -anE'BEGIN{$,="\t&";$\="\t\\\\\n"}$.==1||eof||do{$i//=@F;print@F[map{$_*2-1}(1..$i/2)]}'

这可能适合您:

cal | sed '1d;2{h;s/./ /g;x};/^\s*$/b;G;s/\n/ /;s/^...\(.\{15\}\).*/\1/;s/.../ &\t\&/g;s/\&$/\\\\/' 

Code golf有自己的SE论坛。哪个版本的cal在哪个平台上接受-h选项?@Jonathan:the似乎是唯一的一个。@Jonathan Leffler:可能应该删除-h。在Debian上,当前一天是突出显示的,我相信我曾经遇到过这样的情况:突出显示的ANSI代码在
stdout
是管道时没有被剥离
-h
仅用于删除这些字节。这个问题的标题对于了解它的实际内容毫无用处。+1我一个字都不懂,是时候学习新的perl魔术了;-)我认为
cal-h | perl-F'(.{1,3})'-ane'BEGIN{$,=“\t&“$\=”\t\=”\t\n}下一步如果$.==1;print@F[3,5,7,9,11]”
非常精确且“可靠”。更新的问题。不幸的是,在下个月的天数内没有创建空单元格。。。虽然一开始扩展任何一行可能会修复它。感谢
-p
开关。这是答案(虽然只是我的一个较短版本;-])是的,这是对您的版本的修改。很好的方法,感谢
字段宽度
位。怎么样
cal | awk'BEGIN{FIELDWIDTHS=“3 3”OFS=“\t&”ORS=“\t\n”}FNR=1{print$2,$3,$4,$5,$6;}'
?@JoSo,如果您使用4个空格,而不是像我在这里粘贴输出那样使用
\t
,则会出现这种情况。
cal 02 2012|perl -F'(.{1,3})' -anE'BEGIN{$,="\t&";$\="\t\\\\\n"}$.==1||eof||do{$i//=@F;print@F[map{$_*2-1}(1..$i/2)]}'
cal | sed '1d;2{h;s/./ /g;x};/^\s*$/b;G;s/\n/ /;s/^...\(.\{15\}\).*/\1/;s/.../ &\t\&/g;s/\&$/\\\\/'