Skip to content

Instantly share code, notes, and snippets.

@jonjensen
Created July 21, 2009 05:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonjensen/151139 to your computer and use it in GitHub Desktop.
Save jonjensen/151139 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
# Gmail notes converter
# by Jon Jensen <jon@endpoint.com>
# 2009-07-20
# Copyright 2009 Jon Jensen. Distributed under the GPLv3 license.
# For details see http://www.gnu.org/licenses/gpl-3.0.html
# When importing e.g. Nokia phone contacts into Gmail, most fields are
# crammed into a single Notes field that is useless in the Android phone
# contacts feature. This script takes Gmail-exported contacts in CSV
# (comma-separated values) format and converts those notes into regular
# phone contact entries, which can then be imported back into Gmail.
# Usage:
# ./gmail-notes-converter input.csv > output.csv
use 5.006; use 5.10.0;
use strict;
use warnings;
my %note2description = (
Business => 'Work',
General => 'Personal',
Home => 'Personal',
);
undef $/;
my $file = <>;
my @lines;
# yes, could use Text::CSV, but this works and has no dependencies
while (length($file)) {
my @fields;
# all but final field of row
while (
$file =~ s{
\A
(?:
"([^"]*)"
|
([^,\r\n]*)
)
,
}{}xg
) {
push @fields, $1 // $2;
}
# final field of row
if (
$file =~ s{
\A
(?:
"([^"]*)"
|
([^\r\n]*)
)
\r?\n
}{}x
) {
push @fields, $1 // $2;
}
push @lines, \@fields;
}
my @header = @{ shift @lines };
my %header2column;
{
my $i = 0;
$header2column{$_} = $i++ for @header;
}
for my $line (@lines) {
my %description2number;
my @number;
my %field;
my $i = 0;
for (@$line) {
$field{$header[$i]} = $_ // '';
if ($_ and $header[$i] =~ /^Section (\d+) - Description$/) {
$description2number{$_} = $1;
$number[$1 - 1] = $_;
}
++$i;
}
for (qw( Work Personal Other )) {
next if defined $description2number{$_};
push @number, $_;
my $number = scalar @number;
$description2number{$_} = $number;
$field{"Section $number - Description"} = $_;
}
if (my $notes = delete $field{Notes}) {
for my $note (split /\s*\r?\n\s*/, $notes) {
my ($cat, $type, $value) = ($note =~ /^(\w+)\s+(\w+):\s+(.*)/);
my $title = "Section $description2number{$note2description{$cat}} - \u$type";
warn(qq{$field{Name}: Ignoring note value "$value" that conflicts with existing value "$field{$title}"\n}), next
if $field{$title};
$field{$title} = $value;
}
}
$line = [ map { $field{$_} } @header ];
}
{
no warnings 'uninitialized';
for my $line (\@header, @lines) {
my $out = join(',', map { /[,\n\r"]/ ? qq{"$_"} : $_ } @$line);
# trim trailing empty fields to save space
$out =~ s/,+$//;
print $out, "\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment