2

I have a requirement to generate a file from a table. I am using sed for streaming the data. I want to use a text qualifier if there is any white space in the table column.

Sample input

Unites State | California | UNIX | ABC DE

Expected output

"Unites State" | California | UNIX | "ABC DE"
1
  • This question could use some detail about what exactly you are trying to accomplish. Mar 23, 2017 at 4:34

6 Answers 6

1
$ echo 'Unites State | California | UNIX | ABC DE' | sed -E 's/([^ |]+ +[^|]+)( +\||$)/"\1"\2/g'
"Unites State" | California | UNIX | "ABC DE"
  • Assumes there is always a space before |
  • -E use ERE, some sed versions use -r instead
  • ([^ |]+ +[^|]+) non-space, non-| characters followed by at least one space and then non-| characters
  • ( +\||$) above pattern followed by at least one space and then | or end of line
  • "\1"\2 quote as per requirement
1

Not bad with Perl:

echo $'Unites State | California | UNIX | ABC DE' |perl -pe 's/[a-zA-Z]+[[:space:]]+[a-zA-Z]+/\"$&\"/g'
"Unites State" | California | UNIX | "ABC DE"
1
  • That turns Unites States of America | California | UNIX into "Unites States" "of America" | California | UNIX Mar 27, 2017 at 13:20
1

POSIXly:

sed 's/[^ |][^|]* [^|]*[^| ]/"&"/g'

To account for other blank characters than ASCII space, use:

sed 's/[^[:blank:]|][^|]*[[:blank:]][^|]*[^|[:blank:]]/"&"/g'
0

due to I can not comment, answer here.

perl -pe 's/\w+\s+\w+/\"$&\"/g' 

is more simple to George Vasiliou's answer.

2
  • Actually is the same answer using regex abbreviations : \w for words a-zA-Z0-9 , \s for space Mar 27, 2017 at 13:11
  • But has the same flaw, in that it 3 or 4 word fields are handled badly.
    – Sobrique
    Mar 27, 2017 at 13:47
0

In perl, I'd actually use split:

#!/usr/bin/env perl
use strict;
use warnings;

#iterate data block below (use <> for reading STDIN)
while ( <DATA> ) {
   #split on whitespace|whitespace
   my @fields = split /\s*\|\s*/;
   #transform individual fields
   for ( @fields ) { 
      #check if it contains a space
      next unless m/\s/;
      #if it does, quote
      s/(^|$)/\"/g;
   }
   #print output; 
   print join " \| ", @fields,"\n";
} 

__DATA__
Unites State | California | UNIX | ABC DE

Which outputs:

"Unites State" | California | UNIX | "ABC DE"

But also copes with multi-word fields.

Simplifying this to a one liner, because all the cool kids are:

perl -F'\s*\|\s*' -lane '/\s/&&s/(^|$)/\"/g for @F;print join " \| ",@F'
0
TAB=`echo 'x' | tr 'x' '\011'`; # tab
SPC=`echo 'x' | tr 'x' '\040'`; # space
s="[$SPC$TAB]";                 # whitespace regex
W="[^|$TAB$SPC]";               # building block of a word
echo ' United  States   | California | UNIX|ABC DE' |
sed -e "s/\($W$W*$s$s*\)\{1,\}[^|][^|]*/\"&\"/g"
3
  • Instead of TAB=$(echo 'x' | tr 'x' '\011'); # tab you can just do TAB=$'\t' or TAB=$'\011' Mar 24, 2017 at 1:13
  • @GeorgeVasiliou, $'...' is not standard. Standardly, nowadays, one could use [[:blank:]] or at least TAB=$(printf '\t'), but Rakesh's answer is portable even to systems from the 80s that didn't have printf or $(...), let alone $'...'. Some very old tr implementations have also been known not to support \t, hence the \011. Mar 27, 2017 at 13:12
  • @StéphaneChazelas Yes that's correct. I've updated my answer to reflect the fix. Thanks,
    – user218374
    Mar 27, 2017 at 14:07

You must log in to answer this question.

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