1

I have a huge file that has multiple columns as shown below:

J02-31  23.2  ...
J30-09  -45.4  ...
J05+30  56.1  ...
J00-20  -78.2  ...
J11-54 232.0  ...
...      ...  ...

I would like to replace - with $-$ only in the first column, i.e., my output should be like this:

J02$-$31   23.2  ...
J30$-$09  -45.4  ...
J05+30     56.1  ...
J00$-$20  -78.2  ...
J11$-$54  232.0  ...
...      ...     ...

Is there a way to do this using vi. I know that python/pandas can do it, but I am interested in vi usage.

5
  • I had no idea about it, and I specifically mentioned it in my question. I usually do %s/oldstring/newstring/g for replacement. Commented Jul 28, 2022 at 20:15
  • Not as foolproof as the answers stated below but for given inputs, a simple :%s/-/$-$ would do Commented Aug 1, 2022 at 13:11
  • @LievenKeersmaekers, this would also change the - sign in the second column. Both the answers below are helpful actually. Commented Aug 1, 2022 at 13:17
  • no it wouldn't. Have you tried it on your given sample? Nevertheless, both answer do take care of edge cases (not in your sample) I can imagine being present in your actual data. Already upvoted all :) Commented Aug 1, 2022 at 13:22
  • 1
    You are right, g (global command) would change it everywhere. Omitting it just changes the first column, but the only caveat is that it also ends up changing every - in the last row. Commented Aug 1, 2022 at 13:36

3 Answers 3

4

I'd go with

:%s/^\S*\zs-/$-$/

which means:

  • %s/: apply this substitution for every line
  • ^\S*: read as many non-whitespace characters from the start of the line as possible
  • \zs: actual match start (you could also capture the \S* above instead and insert it back too)
  • -: match the - (note: this will only match the last - in the first column, your question isn't really clear if there can be multiple there)
  • /$-$/: replace the matching part (which is only - thanks to the \zs) with $-$
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. There is only one in the first column, but unfortunately, this command does not work. I also assume that it starts ":". The issue is "pattern not found"
Yes there's a leading : since it's a command. I'll add it. I can't reproduce the error you're seeing though (even with vim -u NONE), vim shouldn't complain a non-matching lines when using %s. Maybe try adding the e flag at the end to specifically ignore those?
This command is working perfectly with a standard vim config. One reason which could explain "pattern not found" is that magic option has been set off; you can check this by running :set magic?; then if you just see "magic", the problem is elsewhere.
awesome! I had space before my first column and obviously that was the culprit.
3

You could do:

:g/^\S*-/s/-/$-$/

Which performs the replacement s/-/$-$/ only on lines which match the pattern /^\S*-/ (ie, those lines which have a - in the first column).

4 Comments

:g/^\S*-/s/-/$-$/ is slower than :%s/-/$-$ and introduces unnecessary complexity for OP's competency level.
@romainl I don't see any "unnecessary complexity". The :g command is extremely useful, and no more "complex" than many other commands. I suspect you would need to be editing a very large file before any performance difference between this and :%s would be noticeable.
It's complexity because OP only needs one command and you give them two (without reference to the doc). It's unnecessary because it doesn't make the task simpler or more reproducible or whatever and it solves a problem (skipping) OP doesn't have. While :g is an immensely useful command in its own right, it's just useless in this context, and the performance bit is just icing on the cake.
@romainl I do not understand your concern. There are not 2 commands here, there is only one. Finding references is trivial: :help :g. Exposing the OP to a command that may be unknown to them is entirely the point of Stack Overflow. Performance is a non-issue.
0

Also:

:%s/\(-\)\|\( .*\)/$\1$\2\3/g

Should work for a more general syntax whith multiple - at fisrt column

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.