如何横向镜像ascii艺术?

Gra*_*ham 6 awk image-processing ascii-art

所以...我知道我可以使用tac或其他一些工具来反转文件中的行顺序,但是如何在其他维度中重新排序,即水平?我正在尝试使用以下awk脚本:

{
    out="";
    for(i=length($0);i>0;i--) {
        out=out substr($0,i,1)}
    print out;
}
Run Code Online (Sandbox Code Playgroud)

这似乎扭转了角色,但它是乱码,我不明白为什么.我错过了什么?

我在awk中这样做,但还有更好的东西吗? sed, 也许?

这是一个例子.输入数据如下所示:

$ cowsay <<<"hello"
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Run Code Online (Sandbox Code Playgroud)

输出看起来像这样:

$ cowsay <<<"hello" | rev
_______ 
> olleh <
------- 
^__^   \        
_______\)oo(  \         
\/\)       \)__(            
| w----||                
||     || 
Run Code Online (Sandbox Code Playgroud)

请注意,无论是使用rev还是我自己的awk脚本,输出都是相同的.正如你所看到的,事情是相反的,但......它被破坏了.

gho*_*oti 7

rev很好,但它不填充输入行.它只是逆转了它们.

你看到的"破坏"是因为一行可能是20个字符长,而下一行可能是15个字符长.在输入文本中,它们共享一个左侧列.但是在输出文本中,他们需要共享一个右侧列.

所以你需要填充.哦,和不对称的逆转,正如约阿希姆所说.

这是我的revawk:

#!/usr/bin/awk -f

# 
length($0)>max {
    max=length($0);
}

{
    # Reverse the line...
    for(i=length($0);i>0;i--) {
        o[NR]=o[NR] substr($0,i,1);
    }
}

END {
    for(i=1;i<=NR;i++) {
        # prepend the output with sufficient padding
        fmt=sprintf("%%%ds%%s\n",max-length(o[i]));
        printf(fmt,"",o[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

(我这样做了gawk;我认为我没有使用任何gawkisms,但如果你使用更经典的awk变体,你可能需要调整它.)

使用方法与使用rev的方式相同.

ghoti@pc:~$ echo hello | cowsay | ./revawk | tr '[[]()<>/\\]' '[][)(><\\/]'
                    _______ 
                   < olleh >
                    ------- 
            ^__^   /        
    _______/(oo)  /         
/\/(       /(__)            
   | w----||                
   ||     ||                
Run Code Online (Sandbox Code Playgroud)

如果您愿意这样做,您甚至可以通过将其添加到最后printf一行来从awk脚本中运行翻译:

        printf(fmt," ",o[i]) | "tr '[[]()<>/\\]' '[][)(><\\/]'";
Run Code Online (Sandbox Code Playgroud)

但我不推荐它,因为它使revawk命令对其他应用程序不那么有用.


Joa*_*son 5

你的线条长度不一样,所以反转奶牛会折断它。您需要做的是将线条“填充”为相同长度,然后反转。

例如;

cowsay <<<"hello" | awk '{printf "%-40s\n", $0}' | rev
Run Code Online (Sandbox Code Playgroud)

将它填充到 40 列,然后反转。

编辑:@ghti 做了一个脚本,肯定能打败这个简单的反向,看看他的回答。


Ste*_*eve 5

这是使用GNU awk和的一种方式rev

运行如下:

awk -f ./script.awk <(echo "hello" | cowsay){,} | rev
Run Code Online (Sandbox Code Playgroud)

内容script.awk:

FNR==NR {
    if (length > max) {
        max = length
    }
    next
}

{
    while (length < max) {
        $0=$0 OFS
    }
}1
Run Code Online (Sandbox Code Playgroud)

或者,这是单行:

awk 'FNR==NR { if (length > max) max = length; next } { while (length < max) $0=$0 OFS }1' <(echo "hello" | cowsay){,} | rev
Run Code Online (Sandbox Code Playgroud)

结果:

                    _______ 
                   > olleh <
                    ------- 
            ^__^   \        
    _______\)oo(  \         
\/\)       \)__(            
   | w----||                
   ||     ||                
Run Code Online (Sandbox Code Playgroud)

-------------------------------------------------- --------------------------------------------

这是另一种使用方式GNU awk:

运行如下:

awk -f ./script.awk <(echo "hello" | cowsay){,}
Run Code Online (Sandbox Code Playgroud)

内容script.awk:

BEGIN {
    FS=""
}

FNR==NR { 
    if (length > max) {
        max = length
    }
    next
}

{
    while (length < max) {
        $0=$0 OFS
    }
    for (i=NF; i>=1; i--) {
        printf (i!=1) ? $i : $i ORS
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,这是单行:

awk 'BEGIN { FS="" } FNR==NR { if (length > max) max = length; next } { while (length < max) $0=$0 OFS; for (i=NF; i>=1; i--) printf (i!=1) ? $i : $i ORS }' <(echo "hello" | cowsay){,}
Run Code Online (Sandbox Code Playgroud)

结果:

                    _______ 
                   > olleh <
                    ------- 
            ^__^   \        
    _______\)oo(  \         
\/\)       \)__(            
   | w----||                
   ||     ||                
Run Code Online (Sandbox Code Playgroud)

-------------------------------------------------- --------------------------------------------

说明:

这是对第二个答案的解释.我假设基本知识awk:

FS=""                 # set the file separator to read only a single character
                      # at a time.

FNR==NR { ... }       # this returns true for only the first file in the argument
                      # list. Here, if the length of the line is greater than the
                      # variable 'max', then set 'max' to the length of the line.
                      # 'next' simply means consume the next line of input

while ...             # So when we read the file for the second time, we loop
                      # through this file, adding OFS (output FS; which is simply
                      # a single space) to the end of each line until 'max' is
                      # reached. This pad's the file nicely.

for ...               # then loop through the characters on each line in reverse.
                      # The printf statement is short for ... if the character is
                      # not at the first one, print it; else, print it and ORS.
                      # ORS is the output record separator and is a newline.
Run Code Online (Sandbox Code Playgroud)

您可能需要了解的其他一些事项:

{,}通配符后缀是用于重复输入的文件名两次的简写.不幸的是,它不是标准的Bourne shell.但是,您可以改为使用:

<(echo "hello" | cowsay) <(echo "hello" | cowsay)
Run Code Online (Sandbox Code Playgroud)

此外,在第一个例子中,{ ... }1是简称{ ... print $0 }

HTH.