+=head2 stats
+
+Dump statistics about field and subfield usage
+
+ print $input->stats;
+
+=cut
+
+sub stats {
+ my $self = shift;
+
+ my $log = $self->_get_logger();
+
+ my $s = $self->{_stats};
+ if (! $s) {
+ $log->warn("called stats, but there is no statistics collected");
+ return;
+ }
+
+ my $max_fld = 0;
+
+ my $out = join("\n",
+ map {
+ my $f = $_ || die "no field";
+ my $v = $s->{fld}->{$f} || die "no s->{fld}->{$f}";
+ $max_fld = $v if ($v > $max_fld);
+
+ my $o = sprintf("%4s %d ~", $f, $v);
+
+ if (defined($s->{sf}->{$f})) {
+ map {
+ $o .= sprintf(" %s:%d%s", $_,
+ $s->{sf}->{$f}->{$_}->{count},
+ $s->{sf}->{$f}->{$_}->{repeatable} ? '*' : '',
+ );
+ } sort keys %{ $s->{sf}->{$f} };
+ }
+
+ if (my $v_r = $s->{repeatable}->{$f}) {
+ $o .= " ($v_r)" if ($v_r != $v);
+ }
+
+ $o;
+ } sort { $a cmp $b } keys %{ $s->{fld} }
+ );
+
+ $log->debug( sub { Dumper($s) } );
+
+ return $out;
+}
+
+=head2 dump
+
+Display humanly readable dump of record
+
+=cut
+
+sub dump {
+ my $self = shift;
+
+ return $self->{dump_rec}->($self, $self->{pos});
+
+}
+
+=head2 modify_record_regexps
+
+Generate hash with regexpes to be applied using l<filter>.
+
+ my $regexpes = $input->modify_record_regexps(
+ 900 => { '^a' => { ' : ' => '^b' } },
+ 901 => { '*' => { '^b' => ' ; ' } },
+ );
+
+=cut
+
+sub _get_regex {
+ my ($sf,$from,$to) = @_;
+ if ($sf =~ /^\^/) {
+ return
+ 's/\Q'. $sf .'\E([^\^]*?)\Q'. $from .'\E([^\^]*?)/'. $sf .'$1'. $to .'$2/';
+ } else {
+ return
+ 's/\Q'. $from .'\E/'. $to .'/g';
+ }
+}
+
+sub modify_record_regexps {
+ my $self = shift;
+ my $modify_record = {@_};
+
+ my $regexpes;
+
+ my $log = $self->_get_logger();
+
+ foreach my $f (keys %$modify_record) {
+ $log->debug("field: $f");
+
+ foreach my $sf (keys %{ $modify_record->{$f} }) {
+ $log->debug("subfield: $sf");
+
+ foreach my $from (keys %{ $modify_record->{$f}->{$sf} }) {
+ my $to = $modify_record->{$f}->{$sf}->{$from};
+ #die "no field?" unless defined($to);
+ $log->debug("transform: |$from| -> |$to|");
+
+ my $regex = _get_regex($sf,$from,$to);
+ push @{ $regexpes->{$f} }, $regex;
+ $log->debug("regex: $regex");
+ }
+ }
+ }
+
+ return $regexpes;
+}
+
+=head2 modify_file_regexps
+
+Generate hash with regexpes to be applied using l<filter> from
+pseudo hash/yaml format for regex mappings.
+
+It should be obvious:
+
+ 200
+ '^a'
+ ' : ' => '^e'
+ ' = ' => '^d'
+
+In field I<200> find C<'^a'> and then C<' : '>, and replace it with C<'^e'>.
+In field I<200> find C<'^a'> and then C<' = '>, and replace it with C<'^d'>.
+
+ my $regexpes = $input->modify_file_regexps( 'conf/modify/common.pl' );
+
+On undef path it will just return.
+
+=cut
+
+sub modify_file_regexps {
+ my $self = shift;
+
+ my $modify_path = shift || return;
+
+ my $log = $self->_get_logger();
+
+ my $regexpes;
+
+ CORE::open(my $fh, $modify_path) || $log->logdie("can't open modify file $modify_path: $!");
+
+ my ($f,$sf);
+
+ while(<$fh>) {
+ chomp;
+ next if (/^#/ || /^\s*$/);
+
+ if (/^\s*(\d+)\s*$/) {
+ $f = $1;
+ $log->debug("field: $f");
+ next;
+ } elsif (/^\s*'([^']*)'\s*$/) {
+ $sf = $1;
+ $log->die("can't define subfiled before field in: $_") unless ($f);
+ $log->debug("subfield: $sf");
+ } elsif (/^\s*'([^']*)'\s*=>\s*'([^']*)'\s*$/) {
+ my ($from,$to) = ($1, $2);
+
+ $log->debug("transform: |$from| -> |$to|");
+
+ my $regex = _get_regex($sf,$from,$to);
+ push @{ $regexpes->{$f} }, $regex;
+ $log->debug("regex: $regex");
+ }
+ }
+
+ return $regexpes;
+}