Ed,

On Fri, Jun 17, 2011 at 10:53:00AM +0100, Edmund Chamberlain wrote:
> Firstly, hello! Its my first time posting and possibly somewhat 
> predictably with a call for help with Unicode stuff.

Ah, yes...

> I've just checked the archive and seen this thread and am having a 
> similar problem, a badly encoded character is causing a while loop 
> through MARC::Batch->next to crash out with:
> 
> utf8 "\x87" does not map to Unicode at 
> /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/Encode.pm line 173.
> 
> I've tried pasting Al's modified decode subroutine and package to the 
> script, but it is still failing. One of the offending records is 
> isolated and attached.
> 
> Any suggestions welcome with regards to further modifying the sub or 
> alternatives to MARC::Batch->next would be welcome. For the scope of the 
> project, I'm limited to large batch files of Marc21.

You could try MARC::Loop, which doesn't care about (or even detect)
character (mis)codings in any way -- it just sees everything as raw
bytes.  Then you can go in and wipe out (or fix) bad byte sequences,
something like this:

    use MARC::Loop qw(marcloop marcbuild);
    marcloop {
        # This code is called once for each record read from standard input
        my ($leader, $fields, $rawref) = @_;
        if ($$rawref =~ /[^\x00-\x7f]/) {
            # The record contains one or more non-ASCII bytes
            foreach my $field (@$fields) {
                my ($tag, $valref) = @$field;
                $strref =~ s{
                    (   # Valid byte sequences for a single character:
                          [\x{00}-\x{7f}]
                        | [\x{c2}-\x{df}][\x{80}-\x{bf}]
                        |         \x{e0} [\x{a0}-\x{bf}][\x{80}-\x{bf}]
                        | [\x{e1}-\x{ec}][\x{80}-\x{bf}][\x{80}-\x{bf}]
                        |         \x{ed} [\x{80}-\x{9f}][\x{80}-\x{bf}]
                        | [\x{ee}-\x{ef}][\x{80}-\x{bf}][\x{80}-\x{bf}]
                        |         \x{f0} [\x{90}-\x{bf}][\x{80}-\x{bf}]
                        | 
[\x{f1}-\x{f3}][\x{80}-\x{bf}][\x{80}-\x{bf}][\x{80}-\x{bf}]
                        |         \x{f4} 
[\x{80}-\x{8f}][\x{80}-\x{bf}][\x{80}-\x{bf}]
                    )
                    |
                    (
                        # Oops! -- invalid byte sequence, we assume all
                        # non-ASCII bytes starting here are bad
                        [^\x00-\x7f]+
                    )
                }{
                    if (defined $2) {
                        # Substitute a "fixed" version of the bad byte sequence
                        print STDERR "Fixing bad byte sequence in field $tag of 
record $.\n";
                        fixed($2);
                    }
                    else {
                        # Leave it unchanged
                        $1;
                    }
                }xeg;
            }
            print marcbuild($leader, $fields);
        }
        else {
            print $$rawref;
        }
    } \*STDIN;
    sub fixed {
        my ($str) = @_;
        # There are any number of actions you might take to "fix" invalid byte
        # sequences; this is just one
        return '?';
    }

The downside is that MARC::Loop is a separate Perl module you'll have to
download from CPAN and install manually.  I wrote it, so I'm biased, but
I think it's good for people who prefer to (or have to) work closer to
the raw MARC record.  (Fixing miscoded records that MARC::Record et al.
couldn't handle was what motivated me to write it in the first place.)

Paul.

-- 
Paul Hoffman <nkui...@nkuitse.com>

Reply via email to