0

I have the following example of a .csv-file

"0a","1a","Short text","abc"
"0b","1bx","Here is a very long text","def"
"0c","1cx","Short text again","ghij"

And now I want to have a maximum of 16 characters in the 3rd column. So "Short text" and "Short text again" would be ok.. but "Here is a very long text" should be "Here is a very l". Even better would be "Here is a very l..."

So that text (of the 3rd column) that is too long is shortened and replaced by '...' at the end.

I found this:

sed '/^.\{0,16\}$/!d' 

But this is not really what I am looking for because it extracts only the whole lines with 0-16 characters.

Maybe you have a better idea?

2
  • 1
    Notes: (1)Here is a very l is indeed 16 characters long, but Here is a very l... is 19. Your "even better would be" kinda contradicts "a maximum of 16 characters". (2) I think in csv spaces outside quotes in a field are not formally allowed. The leading spaces thus may be problematic and cause data to be interpreted not in the way you want. Do you mean "0b","1bx","Here is a very long text","def"? or are the spaces really there? or a tab? If something is there, should it be kept? Jan 26, 2022 at 7:36
  • Yeah, sorry! The leading spaces are only there for clarity. In the csv file there are no leading spaces. Yes, I mean that the text will be limited to 16 characters and the rest of the text will be replaced with "...".
    – Badusche
    Jan 26, 2022 at 7:44

4 Answers 4

0

A better idea – use an actual CSV parser:

#!/usr/bin/env python3
import csv
import sys

rd = csv.reader(sys.stdin)
wr = csv.writer(sys.stdout)

for row in rd:
    if len(row[2]) > 16:
        row[2] = row[2][:15] + "…"
    wr.writerow(row)
0

Not in sed, but in perl.

You may prefix your substitue by a check, in a perl oneliner, to apply a substitute only if the string is longer than the requested size. Here, in a one way catch, the limit not to be catched, is 13+3 chars.

In a second step, if the match is positive, replace the whole string by the 13 chars + 3 dots.

$ echo "12345678901234567" |perl -pe 'if (/^(.{13}).{4}/) { $_="$1..." }'
1234567890123...
$ echo "1234567890123456" |perl -pe 'if (/^(.{13}).{4}/) { $_="$1..." }'
1234567890123456

Obviously, sed is not as complex as it may look, and with the same logic but with two catches: 1/ check if the string is longer than 16 chars 2/ if so, replace by the first 13 chars and 3 dots.

echo "12345678901234567" |sed '/^.\{16\}./ s/^\(.\{13\}\).\+/\1.../'
1234567890123...
echo "1234567890123456" |sed '/^.\{16\}./ s/^\(.\{13\}\).\+/\1.../'
1234567890123456

In a real pseudo-language to enlighten the regular expression:

if /^.{16}./
{
  s/^(.{13}).+/\1.../
}
0
sed 's/^\(".*",".*",".\{0,16\}\).*\(",.*\)$/\1\2/'

".*",".*", first 2 CVS fields

".\{0,16\} opening double quote and up to the first 16 characters of the 3rd CVS field

.* 16th till the end characters

",.*\ closing double quote of the 3rd CVS field and remaining CVS fields

\1 first group: \(".*",".*",".\{0,16\}\)

\2 second group: \(",.*\)

2
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Jan 26, 2022 at 11:04
  • 1
    sed -re 's/^(".*",".*",".{0,16}).*(",.*)$/\1\2/' - slightly easier on the eyes
    – Hannu
    Jan 26, 2022 at 21:10
0

I believe what you are looking for is to truncate a text, not to shorten it.
Assuming you want the output to be 3rd column only (with max-lenght 16 char)
In this case you can use cut command (n=16):

Example

cut -c -16

To extract 3rd column you can also use cut command

Example

cut -d , -f 3

-d is to specify a delimiter
-f is to pick which field
or you can use " as delimiter to get extract text without double-quotes

cut -d \" -f 6

combining them with a pipeline would do the trick

cut -d \" -f 6 file.csv | cut -c -16

Assuming you want to output the whole .csv-file (with 3rd column modified) Kees Trommel's answer or using a scripting language like Python would be an easier approach

0

You must log in to answer this question.

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