Tristan
Tristan

Reputation: 3

AWK reformat portion of results (names) within larger string

My goal is to reformat names from Last First Middle (LFM) to First Middle Last (FML), which are part of a larger string. Here's some sample data:

Name, Address1, Address2
Smith Joe M, 123 Apple Rd, Paris TX
Adams Keith Randall, 543 1st Street, Salinas CA
Price Tiffany, 11232 32nd Street, New York NY
Walker Karen E F, 98 West Ave, Denver CO

What I would like is:

Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO

I know how to reorder the first column, but I end up dropping the rest of the row data:

# Return the first colum via comma seperation (name), then seperate by spaces
# If there are two strings but not three (only a last and first name),
# then change the order to first last.

awk -F, '{print $1}'| awk -F" " '$2!="" && $3=="" {print $2,$1}' >> names.txt
awk -F, '{print $1}'| awk -F" " '$3!="" && $4=="" {print $3,$1,$2}' >> names.txt
...# Continue to iterate column numbers

If there's an easier way to put the last string found and move it to the front I'd like to hear about it, but here's my real interest...

My problem is that I want to reorder the space separated fields of the 1st comma separated field (what I did above), but then also print the rest of the comma separated data.

Is there a way I can store the address info in a variable and append it after the space seperated names?

Alternatively, could I do some kind of nested split?

I'm currently doing this with awk in bash, but am willing to use python/pandas or any other efficient methods.

Thanks for the help!

Upvotes: 0

Views: 94

Answers (4)

perreal
perreal

Reputation: 98088

Using sed, looks terrible but works:

sed -E '2,$s/^([^ ,]*) ([^ ,]*)( [^,]*)?/\2\3 \1/' in

and POSIX version:

sed '2,$s/^\([^ ,]*\) \([^ ,]*\)\( [^,]*\)*/\2\3 \1/' in

output:

Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO

Upvotes: 2

Ed Morton
Ed Morton

Reputation: 204164

$ awk '
    BEGIN { FS=OFS=", " }
    $1 ~ / / {
        last = rest = $1
        sub(/ .*/,"",last)
        sub(/[^ ]+ /,"",rest)
        $1 = rest " " last
    }
    { print }
' file
Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO

Upvotes: 0

James Brown
James Brown

Reputation: 37424

Another awk. This one works with the header line and Madonna (ie. single word fields):

$ awk '                     # using awk
BEGIN{FS=OFS=","}           # csv
{
    n=split($1,a," ")       # split the first field to a
    for(i=n;i>1;i--)        # iterate back from the last element of a
        a[1]=a[i] " " a[1]  # prepending to the first element of a
    $1=a[1]                 # replace the first field with the first element of a
}1' file                    # output

Output:

Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO
Madonna, ...

Upvotes: 0

DYZ
DYZ

Reputation: 57085

The following AWK script, as ugly as it is, works for your inputs (run with awk -F, -f script.awk):

{
 split($1, names, " "); 
 for (i=2; i<=length(names); i++) 
     printf("%s ", names[i]); 
 printf("%s, ", names[1]);
 for(i=2; i<NF; i++)
     printf("%s,", $i);
 print($NF)
}

Input:

Smith Joe M, 123 Apple Rd, Paris TX
Adams Keith Randall, 543 1st Street, Salinas CA
Price Tiffany, 11232 32nd Street, New York NY
Walker Karen E F, 98 West Ave, Denver CO

Output:

Joe M Smith,  123 Apple Rd, Paris TX
Keith Randall Adams,  543 1st Street, Salinas CA
Tiffany Price,  11232 32nd Street, New York NY
Karen E F Walker,  98 West Ave, Denver CO

The same solution in Python:

import sys
import re

for line in sys.stdin:
    parts = re.split('\s*,\s*', line)
    names = parts[0].split()
    print(", ".join([" ".join(names[1:] + names[:1])] + parts[1:]))

Upvotes: 0

Related Questions