+
+sub _copy_move_field {
+ my ( $params ) = @_;
+ my $record = $params->{record};
+ my $fromFieldName = $params->{from_field};
+ my $toFieldName = $params->{to_field};
+ my $regex = $params->{regex};
+ my $field_numbers = $params->{field_numbers} // [];
+ my $action = $params->{action} || 'copy';
+
+ my @from_fields = $record->field( $fromFieldName );
+ if ( @$field_numbers ) {
+ @from_fields = map { $_ <= @from_fields ? $from_fields[ $_ - 1 ] : () } @$field_numbers;
+ }
+
+ my @new_fields;
+ for my $from_field ( @from_fields ) {
+ my $new_field = $from_field->clone;
+ $new_field->{_tag} = $toFieldName; # Should be replaced by set_tag, introduced by MARC::Field 2.0.4
+ if ( $regex and $regex->{search} ) {
+ for my $subfield ( $new_field->subfields ) {
+ my $value = $subfield->[1];
+ ( $value ) = _modify_values({ values => [ $value ], regex => $regex });
+ $new_field->update( $subfield->[0], $value );
+ }
+ }
+ if ( $action eq 'move' ) {
+ $record->delete_field( $from_field )
+ }
+ elsif ( $action eq 'replace' ) {
+ my @to_fields = $record->field( $toFieldName );
+ if ( @to_fields ) {
+ $record->delete_field( $to_fields[0] );
+ }
+ }
+ push @new_fields, $new_field;
+ }
+ $record->append_fields( @new_fields );
+}
+
+sub _copy_move_subfield {
+ my ( $params ) = @_;
+ my $record = $params->{record};
+ my $fromFieldName = $params->{from_field};
+ my $fromSubfieldName = $params->{from_subfield};
+ my $toFieldName = $params->{to_field};
+ my $toSubfieldName = $params->{to_subfield};
+ my $regex = $params->{regex};
+ my $field_numbers = $params->{field_numbers} // [];
+ my $action = $params->{action} || 'copy';
+
+ my @values = read_field({ record => $record, field => $fromFieldName, subfield => $fromSubfieldName });
+ if ( @$field_numbers ) {
+ @values = map { $_ <= @values ? $values[ $_ - 1 ] : () } @$field_numbers;
+ }
+ _modify_values({ values => \@values, regex => $regex });
+ my $dont_erase = $action eq 'copy' ? 1 : 0;
+ _update_subfield({ record => $record, field => $toFieldName, subfield => $toSubfieldName, values => \@values, dont_erase => $dont_erase });
+
+ # And delete if it's a move
+ if ( $action eq 'move' ) {
+ _delete_subfield({
+ record => $record,
+ field => $fromFieldName,
+ subfield => $fromSubfieldName,
+ field_numbers => $field_numbers,
+ });
+ }
+}
+
+sub _modify_values {
+ my ( $params ) = @_;
+ my $values = $params->{values};
+ my $regex = $params->{regex};
+
+ if ( $regex and $regex->{search} ) {
+ $regex->{modifiers} //= q||;
+ my @available_modifiers = qw( i g );
+ my $modifiers = q||;
+ for my $modifier ( split //, $regex->{modifiers} ) {
+ $modifiers .= $modifier
+ if grep {/$modifier/} @available_modifiers;
+ }
+ foreach my $value ( @$values ) {
+ if ( $modifiers =~ m/^(ig|gi)$/ ) {
+ $value =~ s/$regex->{search}/$regex->{replace}/ig;
+ }
+ elsif ( $modifiers eq 'i' ) {
+ $value =~ s/$regex->{search}/$regex->{replace}/i;
+ }
+ elsif ( $modifiers eq 'g' ) {
+ $value =~ s/$regex->{search}/$regex->{replace}/g;
+ }
+ else {
+ $value =~ s/$regex->{search}/$regex->{replace}/;
+ }
+ }
+ }
+ return @$values;
+}