5
Staphylococcus_sp_HMSC14C01-KV792037.1:0.00371647154267842634,Staphylococcus_hominis_VCU122-AHLD01000058.1:0.00124439639436691308)69:0.00227646100249620856,(Staphylococcus_sp_HMSC072E01-KV814990.1:0.00288325234399461859,(((Staphylococcus_hominis_793_SHAE-JUSR01000051.1:0.00594391769091206796,Staphylococcus_pettenkoferi_1286_SHAE-JVVL01000037.1:0.00594050248317441135)

The comma is separating different items and in each item I want to remove everything between - and : including - but keeping :.

How can I do that? So it should look like:

Staphylococcus_sp_HMSC14C01:0.00371647154267842634,Staphylococcus_hominis_VCU122:0.00124439639436691308)69:0.00227646100249620856

I used sed 's/-.*://' 1.file > 2.file but ended up removing the whole file and just kept the first and last values.

1
  • 1
    It looks like your input is a single line, and sed operates a line at a time. Since your regular expression allows for matching .*, the longest (greedy) match is from the first - to the last :. That's why it's deleting everything. You could try replacing the .* with [^,]*, which will force it to stop at the comma between items.
    – Dave M.
    Sep 29, 2017 at 20:51

2 Answers 2

7

.* is a greedy regexp, matching the longest possible match. You need to match the shortest match but match it globally on the whole line. Try

sed 's/-[^:-]*:/:/g' 1.file > 2.file

The character class [^:-] matches anything except colon and dash (and maybe it should match anything except colon only), so the regexp says "dash followed by any number of non-dash, non-colon characters followed by a colon". It then replaces that with a colon (since you wanted to keep that) and does the replacement globally (the trailing g) on the line. If you omit the g, only the first instance would be replaced.

3
  • Thanks Nick, I still do not understand why cannot we say directly sed 's/-*:/:/g' why do we need [^:-]? Sep 29, 2017 at 21:26
  • .* will match the longest sequence of characters possible (that's why it's termed "greedy"). So /-.*:/ says "dash followed by any number of characters followed by colon": that matches the first dash and the last colon in your line (and everything in between) because that's longer than any other match. Is that clear?
    – NickD
    Sep 29, 2017 at 21:30
  • Thank you so much! I've tweaked your regex to help me convert a JSON localization file to an iOS localization file. This was so helpful.
    – Felipe
    Mar 19, 2021 at 16:47
4

Awk solution:

awk -F',' '{ for(i=1;i<=NF;i++) sub(/-[^:-]+/,"",$i) }1' OFS=',' 1.file

  • -F',' - field separator

  • for(i=1;i<=NF;i++) - iterating through all fields of the record

  • sub(/-[^:-]+/,"",$i - substitute the needed sequence (between - and : including - but keeping :)


The output:

Staphylococcus_sp_HMSC14C01:0.00371647154267842634,Staphylococcus_hominis_VCU122:0.00124439639436691308)69:0.00227646100249620856,(Staphylococcus_sp_HMSC072E01:0.00288325234399461859,(((Staphylococcus_hominis_793_SHAE:0.00594391769091206796,Staphylococcus_pettenkoferi_1286_SHAE:0.00594050248317441135)
2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .