【问题标题】:Highlight String Differences突出显示字符串差异
【发布时间】:2016-03-26 10:01:56
【问题描述】:

我正在寻找一种方法来突出两个字符串之间的差异。这个想法是在终端中显示 iconv 更改了哪些字符。这两个字符串都已处理以删除前导和尾随空格,但必须处理内部空格。

RED="$(tput setaf 1)"    ##    Short variables for the tput ->
CYA="$(tput setaf 6)"    ## -> commands to make output strings ->
CLS="$(tput sgr0)"       ## -> easier to read
str1="[String nâmè™]"    # String prior to iconv
str2="[String name[tm]]" # String after iconv -f utf-8 -t ascii//translit

最终我想自动格式化差异,以便它们被 tput 颜色代码包围,我可以回显到终端。

${str1} = 以红色突出显示,两个字符串不通用的字符

${str2} = 以青色突出显示,两个字符串不通用的字符

想要的输出:

output1="[String n${RED}â${CLS}m${RED}è™${CLS}]"
output2="[String n${CYA}a${CLS}m${CYA}e[tm]${CLS}]"

我看到的大多数差异实用程序都在行或单词级别上工作。我正在考虑为第一个差异的字节#解析 cmp 的输出,但我必须重新解析似乎有多个差异。

无论如何,我认为这似乎是一个复杂的过程,所以我只是想确保我没有遗漏明显的解决方案或工具。

现在我在想最简单的方法是格式化每个字符串以将一个字节放在一个新行上,然后我的选项就会打开。

nstr1="$(fold -w1 <<< "$(echo "${str1}")")"
nstr2="$(fold -w1 <<< "$(echo "${str2}")")"
diff <(echo -e "${nstr1}") <(echo -e "${nstr2}")

这是我所能达到的,除非我走在正确的轨道上,否则我不想走得更远。我敢肯定有无数种方法可以做到这一点,但有没有更有效的方法?

【问题讨论】:

  • 我的最终目标在“想要的输出”中说明,但我想我明白你的意思。我认为展示我想如何使用差异输出是相关的,因为它可能会影响如何到达那里。我猜这个问题太宽泛了。如果您认为最好,我会删除该问题。
  • 方法很清楚——解析diff的输出并构造输出有点麻烦,但仍然比重新发明diff好。
  • 希望我把问题说得更清楚一点。 @Thomas,这对我来说似乎也很“麻烦”,这就是为什么我认为我可能会忽略某些东西。
  • 同意 - 我不记得有人做过这个解析器,尽管它让我想起了我做过的事情 herehere
  • 谢谢@Thomas Dickey。这实际上回答了我的问题。如果有更简单的方法,我只是不想先深入研究。我对我的剧本当然不是很挑剔,但似乎是一个值得学习的好项目。

标签: bash shell colors diff


【解决方案1】:

把它们放在一起:

#!/usr/bin/env bash

# Using stdin input, outputs each char. on its own line, with actual newlines
# in the input represented as literal '\n'.
toSingleCharLines() {
  sed 's/\(.\)/\1\'$'\n''/g; s/\n$/\'$'\n''\\n/'
}

# Using stdin input, reassembles a string split into 1-character-per-line output
# by toSingleCharLines().
fromSingleCharLines() {
  awk '$0=="\\n" { printf "\n"; next} { printf "%s", $0 }'
}

# Prints a colored string read from stdin by interpreting embedded color references
# such as '${RED}'.
printColored() {
  local str=$(</dev/stdin)
  local RED="$(tput setaf 1)" CYA="$(tput setaf 6)" RST="$(tput sgr0)"
  str=${str//'${RED}'/${RED}}
  str=${str//'${CYA}'/${CYA}}
  str=${str//'${RST}'/${RST}}
  printf '%s\n' "$str"
}

# The non-ASCII input string.
strOrg='[String nâmè™]'

# Create its ASCII-chars.-only transliteration.
strTransLit=$(iconv -f utf-8 -t ascii//translit <<<"$strOrg")

# Print the ORIGINAL string with the characters that NEED transliteration
# highlighted in RED.
diff --changed-group-format='${RED}%=${RST}' \
  <(toSingleCharLines <<<"$strOrg") <(toSingleCharLines <<<"$strTransLit") |
    fromSingleCharLines | printColored

# Print the TRANSLITERATED string with the characters that RESULT FROM
# transliteration highlighted in CYAN.
diff --changed-group-format='${CYA}%=${RST}' \
  <(toSingleCharLines <<<"$strTransLit") <(toSingleCharLines <<<"$strOrg") |
    fromSingleCharLines | printColored

这会产生:

【讨论】:

  • 我几乎完成了这个,但你打败了我,很高兴你做到了。我喜欢sed 解决方案,并将在我的代码中使用它。
  • 干得好!在 macOS 上,内置 "Terminal" 应用程序设置为模拟 vt100 时,此结果是没有打印颜色输出。然而,将 "Terminal" 声明为 ansixterm-color 会产生所需的颜色输出(即在 “高级” 设置选项卡中更改它)。当设置为vt100 时,有没有办法让它也能成功工作,也许是通过更改tput setaf 的值?
  • 谢谢,RobC,但据我所知,xterm-256color 是默认设置(例如,以访客用户身份尝试),它支持颜色;我不熟悉vt100
  • 是的,同意,你说得对,我刚刚恢复了默认设置(我之前一定已经修改过)。我不完全确定差异,(如果有的话),我一直使用术语 ANSI/VT100 关于颜色/格式代码 - 所以当 “终端” 时有点惊讶app 设置为vt100 没有彩色输出。我想这对我来说已经不太关心了,现在我知道了 macOS 上的默认设置(iTerm 也可以)。
【解决方案2】:

@Thomas Dickey 在 cmets 中提供的答案是,没有比我尝试的方法更容易的工具或过程。

最后,我能够使用以下 difflines 简单地生成“想要的输出”。

diff --changed-group-format="\${RED}%=\${CLS}" <(echo -e "${nstr1}") <(echo -e "${nstr2}")|tr -d '\n'
diff --changed-group-format="\${CYA}%>\${CLS}" <(echo -e "${nstr1}") <(echo -e "${nstr2}")|tr -d '\n'

不幸的是,我还没有弄清楚如何回显输出以解释颜色代码,但这是另一个问题。

【讨论】:

  • 很有趣,但这如何产生字符级别的差异? nstr1nstr2 如何与您的问题中的 str1str2 相关?
  • @mklement0:如果我理解您的要求,我无法在str1str2 上使用diff 来查找要突出显示的字符,因为diff 在行级别上有效.所以nstr1 & nstr2str1 & str2 相同,但每行只有一个字符,所以diff 将在字符级别工作。
  • 啊,我明白了;我忘记了您的 fold -w1 命令来创建每个字符在其自己的行表示中。 +1 的方法。也许您可以修改答案以显示一个独立的工作示例。此外,您的第二个命令错误地包含nstr1 两次。如果您还不知道:您可以在 48 小时后接受自己的答案。
  • 我已经发布了一个解决方案,可以将它们组合在一起。请注意,我使用sed 而不是fold 将字符串拆分为indiv。字符,因为 GNU fold 不支持 Unicode,并且拆分为 bytes 而不是字符。
猜你喜欢
  • 1970-01-01
  • 2022-12-07
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 2022-01-01
  • 2014-06-15
相关资源
最近更新 更多