【问题标题】:Find and replace with keeping part of the string intact?查找并替换并保持部分字符串完整?
【发布时间】:2014-10-28 06:54:05
【问题描述】:

我设法将' time 转换成一个管道字符……

2014/12/04 Test in 1 day' time 0 weeks
2014/12/07 Amazon Prime Ends in 95 days' time 13 weeks
2014/12/24 Christmas in China in 112 days' time 16 weeks

……到这个……

2014/12/04 Test in 1 day | 0 weeks
2014/12/07 Amazon Prime Ends in 95 days | 13 weeks
2014/12/24 Christmas in China in 112 days | 16 weeks

…在sed 's/. time/ |/'的帮助下。

问题:看在上帝的份上,我无法弄清楚如何在数天之前替换 in 字符串,例如in XXX| XXX。显然应该保留天数。

目标:

2014/12/04 Test | 1 day | 0 weeks
2014/12/07 Amazon Prime Ends | 95 days | 13 weeks
2014/12/24 Christmas in China | 112 days | 16 weeks

仅供参考:我正在尝试从remind 输出中构建一个降价表...

echo "| Date | Event | Days Until | ~Weeks |" &&  rem -n | sort | awk '{$0="| "$0};{$3="| "$3};{print $0" |"}' | sed 's/. time/ |/'

【问题讨论】:

  • 如果您使用 awk,则不需要一堆不同的工具。
  • 感谢所有解决方案。我会在接下来的几天里完成它们。

标签: regex shell replace awk sed


【解决方案1】:

你可以使用:

sed 's/ in \([0-9]*\) / | \1 /;s/. time/ |/' file
2014/12/04 Test | 1 day | 0 weeks
2014/12/07 Amazon Prime Ends | 95 days | 13 weeks
2014/12/24 Christmas in China | 112 days | 16 weeks

【讨论】:

  • 感谢这个出色的 sed 解决方案。我肯定从这个中学到了一两件事。问题是:我真的很难在@ed-morton 的 awk 解决方案和你的解决方案之间做出选择。也就是说,我认为我必须采用 Ed 的解决方案,因为它还考虑了我正在组合的脚本的目标。希望这对你没问题。再次感谢。
  • 当然,您有权选择最适合您的答案。
  • 谢谢,我赞成您提出的问题,因为它包含所有必需的详细信息。
【解决方案2】:

试试sed -E "s/ in ([0-9]+)|. time ([0-9]+)/ | \0/g"

分解:

  • | - 匹配两种模式中的任何一种
  • (...) - 捕获组稍后用于恢复匹配的号码
  • [0-9]+ - 匹配任何数字 0-9 中的一个或多个
  • g - 匹配每行中的多个匹配项(您可能不需要 这个)
  • \0 - 将之前捕获的第 0 个匹配组替换为“(...)”

注意:您必须使用-E 参数告诉sed 到use extended expressions in regex

【讨论】:

  • 可悲的是,这整天都像这样输出:0 days.
【解决方案3】:
$ cat tst.awk
BEGIN{
    fmt = "| %s | %s | %s | %s |\n"
    printf fmt,  "Date", "Event", "Days Until", "~Weeks"
}
{
    match($0,/.* in /)
    printf fmt, $1, substr($0,12,RLENGTH-15), $(NF-4), $(NF-1)
}

$ awk -f tst.awk file
| Date | Event | Days Until | ~Weeks |
| 2014/12/04 | Test | 1 | 0 |
| 2014/12/07 | Amazon Prime Ends | 95 | 13 |
| 2014/12/24 | Christmas in China | 112 | 16 |

在最后一列中使用“天”和“周”这两个词似乎是多余的,因此我将它们省略了,但如果您喜欢在打印中添加适当的字段,可以添加它们。顺便说一句,上面使用了您的原始文件作为输入:

$ cat file
2014/12/04 Test in 1 day' time 0 weeks
2014/12/07 Amazon Prime Ends in 95 days' time 13 weeks
2014/12/24 Christmas in China in 112 days' time 16 weeks

如果您更喜欢表格输出格式,那没问题:

$ cat tst.awk
BEGIN{
    fmt = "| %10s | %20s | %10s | %6s |\n"
    printf fmt,  "Date   ", "Event       ", "Days Until", "~Weeks"
}
{
    match($0,/.* in /)
    printf fmt, $1, substr($0,12,RLENGTH-15), $(NF-4), $(NF-1)
}
$
$ awk -f tst.awk file
|    Date    |         Event        | Days Until | ~Weeks |
| 2014/12/04 |                 Test |          1 |      0 |
| 2014/12/07 |    Amazon Prime Ends |         95 |     13 |
| 2014/12/24 |   Christmas in China |        112 |     16 |

如果 awk 脚本不在单独的文件中:

awk '
BEGIN{
    fmt = "| %s | %s | %s | %s |\n"
    printf fmt,  "Date", "Event", "Days Until", "~Weeks"
}
{
    match($0,/.* in /)
    printf fmt, $1, substr($0,12,RLENGTH-15), $(NF-4), $(NF-1)
}
' file

如果你有一种强烈的愿望要把它全部塞到一条线上(我不会这样做):

awk 'BEGIN{ fmt = "| %s | %s | %s | %s |\n"; printf fmt,  "Date", "Event", "Days Until", "~Weeks" } { match($0,/.* in /); printf fmt, $1, substr($0,12,RLENGTH-15), $(NF-4), $(NF-1) }' file

【讨论】:

  • 感谢您的贡献。我想我需要做一些 awk 教程。看起来太甜了,不能再忽略它了——尤其是如果一个人不愿意为 sed 编写正则表达式(……然后正确地转义它)。只是出于好奇。是否可以将 tst.awk 的内容放在一个单行中,以便我可以在 shell 脚本中使用它而无需调用另一个外部文件?只是想知道是否值得探索这种可能性,或者这是一个失败的案例。
  • 是的,但是将它全部塞到一行中并没有什么好处,只需将其放在单引号之间,然后调用为awk 'BEGIN{...}' file,即 tst.awk 的内容原样位于单引号之间.我也会更新答案以表明这一点。
  • 要学习 awk,请潜入新闻组 comp.lang.awk 并获得 Arnold Robbins 的《Effective Awk Programming, Third Edition》一书。
【解决方案4】:
(in)(?=\s*\d+)

这行得通。查看演示。

http://regex101.com/r/pP3pN1/26

您也可以将这两种情况组合在一起。

(in)(?=\s*\d+)|' time

并替换为 |

http://regex101.com/r/pP3pN1/27

【讨论】:

  • 发布一个正则表达式并说“这有效”是没有用的。不同的正则表达式在不同的工具中意味着不同的东西,所以只有能够说“这个正则表达式在工具 X 中产生预期的输出”并告诉我们工具 X 是什么才有用。例如,发布的正则表达式肯定不会在任何 awk 或 [大多数?] seds 中产生预期的输出。
【解决方案5】:

这是另一个答案。这个不使用| (OR) 运算符,因此它可能被认为对意外替换更安全。

sed -r "s/in ([0-9]+) (day(s)?)' time/| \1 \2 |/g" file

它仍然假定必须出现 daydays 一词。

【讨论】:

  • 我想我应该提到我使用的是 Mac。因此,-r 不可用。 :(
猜你喜欢
  • 2016-07-07
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 1970-01-01
  • 2013-07-10
  • 1970-01-01
相关资源
最近更新 更多