1

I managed to convert ' time into a pipe character going from this…

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

… to this…

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

… with the help of sed 's/. time/ |/'.

The problem: I can't for the love of god figure out how to replace the in string before days count, e.g. in XXX with | XXX. Obviously the number of days should be kept.

Goal:

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

For reference purposes: I'm trying to build a markdown table out of a remind output via…

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

5 Answers5

3

You can use:

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
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Thanks for this excellent sed solution. I definitely learned a thing or two with this one. The thing is: I'm really having a tough choosing between @ed-morton's awk solution and yours. That said, I think I have to go with Ed's solution since it also takes into consideration what the goal of the script is I'm putting together. Hope this is okay with you. Thanks again. – patrick Sep 07 '14 at 15:46
  • Sure that's your prerogative to choose whatever answer works best for you. – anubhava Sep 07 '14 at 15:50
  • Thanks, I upvoted your question for being a good problem with all the required details. – anubhava Sep 07 '14 at 16:01
1

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

Breaking it down:

  • | - match either of two patterns
  • (...) - capture group used later to restore matched numbers
  • [0-9]+ - match one or more of any digit 0-9
  • g - match multiple occurrences within each line (you may not need this)
  • \0 - replace the 0th matched group previously captured with "(...)"

Note: you have to use the -E parameter to tell sed to use extended expressions in regex.

Community
  • 1
  • 1
Yiyang Fei
  • 51
  • 5
0
(in)(?=\s*\d+)

This works.See demo.

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

You can also club both conditions together.

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

and replace by |

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

vks
  • 67,027
  • 10
  • 91
  • 124
  • 1
    Posting a regexp and saying "This works" is not useful. Different regexps mean different things in different tools so it's only useful to be able to say "This regexp produces the expected output in tool X" and tell us what tool X is. The posted regexp for example will certainly not produce the expected output in any awk or [most?] seds. – Ed Morton Sep 03 '14 at 17:40
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 |

Having the words "days" and "weeks" in the last columns seems redundant so I left them out but you can add them if you like just be adding the appropriate fields to the print. The above used your original file as input, by the way:

$ 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

and if you prefer a more tabular output format, that's no problem:

$ 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 |

Without the awk script being in a separate 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

and if you feel a burning desire to cram it all onto one line (I wouldnt do this):

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
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • Thanks for this contribution. I think I need to do some awk tutorials. Looks too sweet to ignore it any longer – especially if one isn't to comfortable writing a regex for sed (… and then escaping it correctly). Just out of curiosity. Is it possible to put the contents of `tst.awk` in a one-liner so that I can use it in a shell script without calling another external file? Just wanted to know if it's worth exploring this possibility or if it's a lost case. – patrick Sep 07 '14 at 15:53
  • Yes but there's no benefit of cramming it all onto one line, just put it between single quotes and call is as `awk 'BEGIN{...}' file`, ie with the contents of tst.awk as-is between the single quotes. I'll update the answer to show that too. – Ed Morton Sep 07 '14 at 16:07
  • To learn awk, lurk in the newsgroup comp.lang.awk and get the book Effective Awk Programming, Third Edition, by Arnold Robbins. – Ed Morton Sep 07 '14 at 16:22
0

This is yet another answer. This one does not use | (OR) operator, so it may be considered safer against accidental substitutions.

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

It still assumes that there has to appear either the word day or days.

LatinSuD
  • 1,779
  • 12
  • 19