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"
  • This question could use some detail about what exactly you are trying to accomplish. – Stephen Rauch Mar 23 '17 at 4:34
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"
  • That turns Unites States of America | California | UNIX into "Unites States" "of America" | California | UNIX – Stéphane Chazelas Mar 27 '17 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.

  • Actually is the same answer using regex abbreviations : \w for words a-zA-Z0-9 , \s for space – George Vasiliou Mar 27 '17 at 13:11
  • But has the same flaw, in that it 3 or 4 word fields are handled badly. – Sobrique Mar 27 '17 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"
  • Instead of TAB=$(echo 'x' | tr 'x' '\011'); # tab you can just do TAB=$'\t' or TAB=$'\011' – George Vasiliou Mar 24 '17 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. – Stéphane Chazelas Mar 27 '17 at 13:12
  • @StéphaneChazelas Yes that's correct. I've updated my answer to reflect the fix. Thanks, – user218374 Mar 27 '17 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.