1

我想反转一堆文件中的所有颜色值。颜色都是十六进制格式#ff3300,因此可以使用 sed 命令按字符进行反转

y/0123456789abcdef/fedcba9876543210/

如何遍历所有颜色匹配并在 sed 或 awk 中进行字符转换?

编辑:

样本输入:

random text... #ffffff_random_text_#000000__
asdf#00ff00
asdfghj

所需的输出:

random text... #000000_random_text_#ffffff__
asdf#ff00ff
asdfghj
4

4 回答 4

2

这可能对您有用(GNU sed):

sed '/#[a-f0-9]\{6\}\>/!b
s//\n&/g
h
s/[^\n]*\(\n.\{7\}\)[^\n]*/\1/g
y/0123456789abcdef/fedcba9876543210/
H
g
:a;s/\n.\{7\}\(.*\n\)\n\(.\{7\}\)/\2\1/;ta
s/\n//' file

解释:

  • /#[a-f0-9]\{6\}\>/!b摆脱不包含所需模式的行
  • s//\n&/g在每个模式前加上换行符
  • h将此复制到保留空间
  • s/[^\n]*\(\n.\{7\}\)[^\n]*/\1/g删除除所需模式之外的所有内容
  • y/0123456789abcdef/fedcba9876543210/转换模式
  • H将新模式附加到保留空间
  • g用保持空间的内容覆盖模式空间
  • :a;s/\n.\{7\}\(.*\n\)\n\(.\{7\}\)/\2\1/;ta用新模式替换旧模式。
  • s/\n//H从命令中删除换行符。
于 2012-07-05T16:06:16.690 回答
2

编辑:我根据您的编辑更改了我的回复。

好的,sed可能会导致处理困难。awk可以或多或少轻松地做到这一点,但我发现perl这项任务更容易:

$ perl -pe 's/#[0-9a-f]+/$&=~tr%0123456789abcdef%fedcba9876543210%r/ge' <infile >outfile

基本上你找到了模式,然后执行右侧,它在匹配上执行 tr,并替换那里的值。

于 2012-07-05T09:51:57.053 回答
2

倒置真的是减法。要反转一个十六进制,你只需从ffffff.
考虑到这一点,您可以构建一个简单的脚本来处理每一行,提取十六进制,反转它们,然后将它们注入回行。


这仅使用Bash(请参阅数组,printf -v+=)(那里没有外部工具):

#!/usr/bin/env bash

[[ -f $1 ]] || { printf "error: cannot find file: %s\n" "$1" >&2; exit 1; }

while read -r; do
    # split line with '#' as separator
    IFS='#' toks=( $REPLY )
    for tok in "${toks[@]}"; do
        # extract hex
        read -n6 hex <<< "$tok"
        # is it really a hex ?
        if [[ $hex =~ [0-9a-fA-F]{6} ]]; then
            # compute inversion
            inv="$((16#ffffff - 16#$hex))"
            # zero pad the result
            printf -v inv "%06x" "$inv"
            # replace hex with inv
            tok="${tok/$hex/$inv}"
        fi
        # build the modified line
        line+="#$tok"
    done
    # print the modified line and clean it for reuse
    printf "%s\n" "${line#\#}"
    unset line
done < "$1"

像这样使用它:

$ ./invhex infile > outfile

测试用例输入:

random text... #ffffff_random_text_#000000__
asdf#00ff00
bdf#cvb_foo
asdfghj
#bdfg

处理后的输出:

random text... #000000_random_text_#ffffff__
asdf#ff00ff
bdf#cvb_foo
asdfghj
#bdfg
于 2012-07-05T13:14:59.687 回答
1

这有效...

cat test.txt |sed -e 's/\#\([0123456789abcdef]\{6\}\)/\n\#\1\n/g' |sed -e ' /^#.*/ y/0123456789abcdef/fedcba9876543210/' | awk '{lastType=type;type= substr($0,1,1)=="#";} type==lastType && length(line)>0 {print line;line=$0} type!=lastType {line=line$0} length(line)==0 {line=$0} END {print line}'

第一个 sed 命令在十六进制代码周围插入换行符,然后可以在所有以散列开头的行上进行替换。可能有一个优雅的解决方案可以再次合并这些行,但是 awk 命令可以完成这项工作。唯一的假设是不会有两个直接紧随其后的十六进制代码。如果是这样,则必须修改此步骤。

于 2012-07-05T11:50:24.823 回答