找到并替换保持部分字符串完好无损?

时间:2014-09-03 17:06:05

标签: regex shell replace awk sed

我设法将' 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 。显然应该保留天数。

目标:

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

供参考:我正试图通过...... {/ p>从remind输出构建一个降价表

{{1}}

5 个答案:

答案 0 :(得分:3)

您可以使用:

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

答案 1 :(得分:1)

尝试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

答案 2 :(得分:0)

(in)(?=\s*\d+)

这很有效。参见演示。

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

你也可以同时兼顾两种情况。

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

并替换为|

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

答案 3 :(得分:0)

$ 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

答案 4 :(得分:0)

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

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

它仍然假设必须出现单词daydays