Inserting lines into text files, or howto "fix" vCards having no n: entry

Discussion in 'Perl Misc' started by analogquack@gmail.com, Jun 7, 2006.

  1. Guest

    I am needing to copy a line of text within a text file and insert a
    slightly modified version of that line at a different point in same
    file. I have had difficulty finding any text I can grok which would
    assist me in this matter.

    If you don't care about the details of my specific project, any general
    example would be very helpful and gratefully accepted. If you do care
    about the details (or if it helps someone else who is trying to perform
    the same task) the specifics of my challenge and the script I am
    working with follow.

    The goal is to add N: and FN: entries into vCards having none by
    copying the data from the ORG: line. In English, some contacts have
    company names but no first and last name, which are represented on the
    N: and FN: lines. Some address book apps expect to have a line in the
    N: or FN: fields (Outlook for example) while others don't care (Palm
    Desktop for example).

    To be specific, the text files look like this:

    BEGIN:VCARD
    VERSION:2.1
    N:LastName;FirstName
    FN:FirstName LastName
    TITLE:Title
    ORG:Company
    ADR;WORK:;;WorkAddress;WorkCity;WorkState;WorkZip;WorkCountry
    URL;WORK:Website
    TEL;WORK:Work#

    When there is no N: or FN: fields, they would look like so:

    BEGIN:VCARD
    VERSION:2.1
    TITLE:Title
    ORG:Company
    ADR;WORK:;;WorkAddress;WorkCity;WorkState;WorkZip;WorkCountry
    URL;WORK:Website
    TEL;WORK:Work#

    I need to copy the ORG: line, "ORG:Company" in this example, and have
    it inserted just below the VERSION:2.1 line like so:

    BEGIN:VCARD
    VERSION:2.1
    N:Company
    FN:Company
    TITLE:Title
    ORG:Company
    ADR;WORK:;;WorkAddress;WorkCity;WorkState;WorkZip;WorkCountry
    URL;WORK:Website
    TEL;WORK:Work#

    I would like to integrate this into a Perl script I have found in a
    prior thread which works well except for this one lacking feature. The
    script parses a single Palm Desktop-exported vCard file having multiple
    contacts within it and output separate vCard files, one for each
    contact. If I could integrate the two functions I would be able to
    transform my thousand or so contacts in one fell swoop into files that
    can be imported into Outlook. =)

    Here is the script as I am currently using it:

    #!/usr/bin/perl -w
    use strict;
    # vcard 2.1 - rfc2425,rfc2426

    my $pathname = 'C:/No_Install/_Analog/Office/Output';
    my $sourcefilename = '../Palm.vcf';

    $/ = ''; # set paragraph mode
    open SOURCE, "< $pathname/$sourcefilename"
    or die "Couldn't open $sourcefilename for reading: $!";
    while ( <SOURCE> ) {
    chomp;
    my $sinkfilename;
    if ( /^(fn[;:].+)/im ) {
    ( undef, $sinkfilename ) = split /(?<!\\):/, $1, 2;
    }
    elsif ( /^(n[;:].+)/im ) {
    ( undef, $sinkfilename ) = split /(?<!\\):/, $1, 2;
    # n: field is "lastname;firstname"
    # change to "firstname lastname"
    $sinkfilename = join ' ', reverse split /(?<!\\);/,
    $sinkfilename;
    }
    $sinkfilename =~ s/[^\w~,\- ]//g;
    my $count = '';
    if ( -e "$pathname/$sinkfilename" ) {
    1 while -e "$pathname/" . ++$count . "$sinkfilename" . ".vcf";
    }
    $sinkfilename .= ".vcf" ;
    open SINK, "> $pathname/$count$sinkfilename"
    or die "Couldn't open $count$sinkfilename for writing: $!";
    print SINK "$_\n" or die "can't write $count$sinkfilename: $!";
    close SINK or die "couldn't close $count$sinkfilename: $!";
    }
    close SOURCE or die "couldn't close $sourcefilename: $!";

    __END__


    You can see the thread I gaffed this from here for reference:
    http://groups.google.com/group/comp...st&q=split palm vcard&rnum=1#79e269b866d12028
    , Jun 7, 2006
    #1
    1. Advertising

  2. Re: Inserting lines into text files, or howto "fix" vCards having

    wrote:
    > I am needing to copy a line of text within a text file and insert a
    > slightly modified version of that line at a different point in same
    > file.


    perldoc -q "insert a line"

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Jun 7, 2006
    #2
    1. Advertising

  3. Guest

    Thank you. Your clue results in a helpful pointer to the Tie::File
    module.

    It will take me quite a bit to figure out the rest of the puzzle. If
    anyone else has any clues regarding how I might use the Tie::File
    module to accomplish this task, I'd appreciate it.

    Please understand that I am a Perl novice and the following is the best
    I can do to describe where I'm trying to go with this. I've got to use
    some plain English pseudocode where I've got no idea how to write the
    Perl stuff in order to convey myself. I imaging it would be something
    like (assuming this processing is done before the vCard file is split
    into multiple vCards):

    use Tie::File

    tie @array, 'Tie::File', $sourcefilename or die;

    for (@array) {
    If, in a given paragraph there are no lines beginning with "N:" or
    "FN:" then {
    $org = the line of this paragraph beginning with "ORG:"
    $n = $org except we've replaced "ORG" with "N"
    $fn = $org except we've replaced "ORG" with "FN"
    Insert $n and $fn as two new lines just after the line of this
    paragraph which begins with "VERSION:2.1"
    }
    }

    How would I go about completing the "for" statement in proper Perl?

    I'm providing an example vCard to complete the illustration, with the
    first record (paragraph) being a record which should be ignored,
    followed by three that should have "N:" and "FN:" lines inserted into
    them:

    BEGIN:VCARD
    VERSION:2.1
    N:LastName;FirstName
    FN:FirstName LastName
    TITLE:Title
    ORG:Company
    ADR;WORK:;;WorkAddress;WorkCity;WorkState;WorkZip;WorkCountry

    BEGIN:VCARD
    VERSION:2.1
    ORG:1 Day Paint and Body
    ADR;WORK:;;27592 Camino Capistrano;Laguna Niguel;CA
    NOTE:7:30am-6pm Mon-Fri
    TEL;WORK:(949) 582-1821
    X-Palm-Custom1:http://www.1daypaint.com/
    END:VCARD

    BEGIN:VCARD
    VERSION:2.1
    ORG:2 Advanced Studios
    ADR;WORK:;;65 Enterprise;Aliso Viejo;CA;92656
    TEL;WORK:949.443.2112
    TEL;FAX:949.330.7581
    EMAIL:
    X-Palm-Custom1:http://www.2advanced.com/
    END:VCARD

    BEGIN:VCARD
    VERSION:2.1
    ORG:604 List
    X-Palm-Custom1:www.party.net
    END:VCARD
    , Jun 7, 2006
    #3
  4. Re: Inserting lines into text files, or howto "fix" vCards having

    wrote:
    > Please understand that I am a Perl novice and the following is the best
    > I can do to describe where I'm trying to go with this.


    <snip>

    > use Tie::File
    >
    > tie @array, 'Tie::File', $sourcefilename or die;
    >
    > for (@array) {
    > If, in a given paragraph there are no lines beginning with "N:" or
    > "FN:" then {
    > $org = the line of this paragraph beginning with "ORG:"
    > $n = $org except we've replaced "ORG" with "N"
    > $fn = $org except we've replaced "ORG" with "FN"
    > Insert $n and $fn as two new lines just after the line of this
    > paragraph which begins with "VERSION:2.1"
    > }
    > }


    Then you are not ready for the task. If you want to learn Perl, check
    out http://learn.perl.org/

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Jun 7, 2006
    #4
  5. Re: Inserting lines into text files, or howto "fix" vCards having

    wrote:
    > I am needing to copy a line of text within a text file and insert a
    > slightly modified version of that line at a different point in same
    > file. I have had difficulty finding any text I can grok which would
    > assist me in this matter.
    >
    > If you don't care about the details of my specific project, any general
    > example would be very helpful and gratefully accepted. If you do care
    > about the details (or if it helps someone else who is trying to perform
    > the same task) the specifics of my challenge and the script I am
    > working with follow.
    >
    > The goal is to add N: and FN: entries into vCards having none by
    > copying the data from the ORG: line. In English, some contacts have
    > company names but no first and last name, which are represented on the
    > N: and FN: lines. Some address book apps expect to have a line in the
    > N: or FN: fields


    That is probably because according to http://www.imc.org/pdi/vcard-21.rtf the
    N field is REQUIRED.

    > (Outlook for example) while others don't care (Palm
    > Desktop for example).
    >
    > [snip]
    >
    > I would like to integrate this into a Perl script I have found in a
    > prior thread which works well except for this one lacking feature. The
    > script parses a single Palm Desktop-exported vCard file having multiple
    > contacts within it and output separate vCard files, one for each
    > contact. If I could integrate the two functions I would be able to
    > transform my thousand or so contacts in one fell swoop into files that
    > can be imported into Outlook. =)
    >
    > Here is the script as I am currently using it:


    Since I posted the script you are borrowing I might as well post this update
    as well. :) I did some testing so hopefully this will work correctly.

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

    my $pathname = 'C:/No_Install/_Analog/Office/Output';
    my $sourcefilename = '../Palm.vcf';

    $/ = ''; # set paragraph mode

    open SOURCE, '<', "$pathname/$sourcefilename"
    or die "Cannot open '$sourcefilename' $!";

    while ( <SOURCE> ) {
    chomp;

    my $fn;
    if ( /^(fn[;:].+)/im ) {
    $fn = ( split /(?<!\\):/, $1, 2 )[ 1 ];
    }

    my $n;
    if ( /^(n[;:].+)/im ) {
    $n = ( split /(?<!\\):/, $1, 2 )[ 1 ];
    # n: field is "lastname;firstname"
    # change to "firstname lastname"
    $n = join ' ', reverse split /(?<!\\);/, $n;
    }

    my $org;
    if ( !$fn && !$n && /^(org[;:].+)/im ) {
    $org = ( split /(?<!\\):/, $1, 2 )[ 1 ];
    $fn = $n = $org;
    s/(^version:.*\n)/$1N:$n\nFN:$fn\n/im;
    }

    ( my $sinkfilename = $n || $fn || $org ) =~ s/[^\w~,\- ]+//g;
    my $count = '';
    if ( -e "$pathname/$sinkfilename.vcf" ) {
    1 while -e "$pathname/" . ++$count . "$sinkfilename.vcf";
    }
    $sinkfilename = "$count$sinkfilename.vcf";

    open SINK, '>', "$pathname/$sinkfilename"
    or die "Cannot open '$sinkfilename' $!";
    print SINK "$_\n"
    or die "Cannot write '$sinkfilename' $!";
    close SINK
    or die "Cannot close '$sinkfilename' $!";
    }

    close SOURCE or die "Cannot close '$sourcefilename' $!";

    __END__



    John
    --
    use Perl;
    program
    fulfillment
    John W. Krahn, Jun 7, 2006
    #5
  6. Guest

    Woah!

    John,

    I envy your skills and am grateful for your contribution. I'll let you
    know how this works out for me.

    I'll also do my best to learn the logic of your parsing and the syntax
    of your regex so as to be able to better formulate my questions in the
    future. =)

    Gunnar,

    While I respectfully understand your stance of "you need to do some
    Perl literacy work", I'll note here I have already read two complete
    O'Reilly books on Perl and I still struggle to understand it. The
    language itself is truly obfuscated on its own. but regex of any flavor
    has really never been easy to work out as a beginner for any task
    beyond the most simple pattern matching. (At least that would be the
    typical experience as conveyed to me by most humans I interact with,
    though I know many people seem to have natural knack for such things.)

    The point of this being to say that I feel community forums such as
    Usenet are the appropriate place to learn the more difficult aspects of
    any language. Also it should be said that I already have done the RTFM
    type work on my end but apparently am just too thick-skulled to grok
    this stuff without a little hand-holding.

    That being said, I appreciate your tolerance of my my newbie naiveté
    and the link to http://learn.perl.org/ . I'll review the material
    there. Thanks for the tip. ;)
    , Jun 7, 2006
    #6
  7. DJ Stunks Guest

    John W. Krahn wrote:
    > wrote:
    > > I would like to integrate this into a Perl script I have found in a
    > > prior thread which works well except for this one lacking feature. The
    > > script parses a single Palm Desktop-exported vCard file having multiple
    > > contacts within it and output separate vCard files, one for each
    > > contact. If I could integrate the two functions I would be able to
    > > transform my thousand or so contacts in one fell swoop into files that
    > > can be imported into Outlook. =)
    > >
    > > Here is the script as I am currently using it:

    >
    > Since I posted the script you are borrowing I might as well post this update
    > as well. :) I did some testing so hopefully this will work correctly.


    'borrowing' would indicate it's going to be returned afterward, right?
    :p

    anyhow, just thought I'd mention that there's quite a few modules on
    CPAN for parsing vFiles, and getting and setting vCard (and vCalendar)
    attributes in an OO way...

    y'all might want to check-ch-check-check-check-ch-check it out.

    -jp
    DJ Stunks, Jun 7, 2006
    #7
  8. Ben Morrow Guest

    Quoth :
    > While I respectfully understand your stance of "you need to do some
    > Perl literacy work", I'll note here I have already read two complete
    > O'Reilly books on Perl and I still struggle to understand it.


    Which two? I would recommend starting with 'Learning Perl' by Randal
    Schwartz, moving on to the Camel Book ('Programming Perl', by Larry Wall
    et al.). If those are the two, then you perhaps need to read them again,
    more carefully. In particular, if you are learning programming, as
    opposed to simply learning Perl, then you must expect it to take a lot
    of work. THe concepts involved are not easy.

    > The language itself is truly obfuscated on its own.


    Oi! :)
    I wouldn't recommend saying that around here, especially from your
    position as someone who doesn't understand Perl yet. From my POV,
    (well-written) Perl is one of the clearest languages I've used, and the
    most like English in feel (as opposed to the COBOL/SQL/AppleScript-type
    languages, which look like English but don't feel like it). If, when you
    have a decent grasp of the language, you still feel this, then I would
    suggest using something else. This is not meant to put you off using
    Perl, or to be disparaging(sp?): different people have different tastes,
    and you'll probably be happier writing in a language which fits yours.

    > but regex of any flavor has really never been easy to work out as a
    > beginner for any task beyond the most simple pattern matching. (At
    > least that would be the typical experience as conveyed to me by most
    > humans I interact with, though I know many people seem to have natural
    > knack for such things.)


    This is certainly true, and the remedy for it is practice. In the
    meanwhile, don't be ashamed to use simpler solutions you understand
    better. Certainly make heavy use of the /x switch and comments in your
    regexes: they will help you understand them later. And don't be put off
    if people here say things like 'don't use index for that, use a regex:
    it's more Perlish': they are (mostly) honestly trying to help you use
    the language as designed. As a rule, if you've read their code and made
    a good effort to understand it from the docs (which can be a little
    tricky to understand themselves, at times, I know), and you provide
    evidence of this, people will be willing to explain things further until
    you do understand them.

    Ben

    --
    Musica Dei donum optimi, trahit homines, trahit deos. |
    Musica truces mollit animos, tristesque mentes erigit.|
    Musica vel ipsas arbores et horridas movet feras. |
    Ben Morrow, Jun 7, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?Um9iZXJ0IEhhbHN0ZWFk?=

    Problem with text when inserting into text box

    =?Utf-8?B?Um9iZXJ0IEhhbHN0ZWFk?=, Apr 27, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    395
    Somchai U.
    Apr 27, 2004
  2. Xah Lee
    Replies:
    22
    Views:
    1,094
    Tim Roberts
    Mar 21, 2006
  3. Roy Schestowitz

    Inserting Lines into HTML Header

    Roy Schestowitz, Jun 12, 2005, in forum: HTML
    Replies:
    10
    Views:
    980
    Andy Dingley
    Jun 13, 2005
  4. Xah Lee
    Replies:
    23
    Views:
    1,032
    Tim Roberts
    Mar 21, 2006
  5. Xah Lee
    Replies:
    21
    Views:
    751
    Tim Roberts
    Mar 21, 2006
Loading...

Share This Page