From cb05a0924a42079a6c2947c5f61f334c307cbb4d Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 27 Feb 2026 14:32:28 +0000 Subject: [PATCH] Bug 35104: Use Unicode Control Pictures in nonxml_stripped context snippets Instead of a [U+XXXX] marker, the context snippet now shows a visible glyph in place of the stripped character: C0 controls (U+0000-U+001F) -> Unicode Control Pictures (U+2400-U+241F) DEL (U+007F) -> U+2421 SYMBOL FOR DELETE (?) other non-XML characters -> U+FFFD REPLACEMENT CHARACTER (?) The first line of the error message is unchanged, continuing to identify the character by its decimal value and U+XXXX code: 336$a: invalid char value 8 (U+0008) at position 12 t $xtac arr?\ $btxt V $2rdac ontent ^ --- Koha/Biblio/Metadata.pm | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Koha/Biblio/Metadata.pm b/Koha/Biblio/Metadata.pm index 7207eec2f08..6cb83e2a6af 100644 --- a/Koha/Biblio/Metadata.pm +++ b/Koha/Biblio/Metadata.pm @@ -394,26 +394,35 @@ a bad character, and its ordinal C<$char_ord>, returns a two-line string: =over 4 =item * Line 1 – up to 30 characters of context either side of the bad -character, with the bad character replaced by a C<[U+XXXX]> marker and -ellipses when the window is truncated. +character, with the bad character replaced by a visible glyph (Unicode +Control Pictures U+2400–U+241F for C0 controls, C<␡> for DEL, C +otherwise) and ellipses when the window is truncated. -=item * Line 2 – a caret (C<^>) aligned beneath the start of the marker. +=item * Line 2 – a caret (C<^>) aligned beneath the visible glyph. =back Example output (4-space indent): - ...arr \ [U+0008]$btxt V $2rdac ontent - ^ + t $xtac arr␈\ $btxt V $2rdac ontent + ^ =cut sub _context_snippet { my ( $chars_ref, $pos_0, $char_ord ) = @_; - my $marker = sprintf '[U+%04X]', $char_ord; - my $last = $#{$chars_ref}; - my $win = 30; + # Visible stand-in for the removed character: + # C0 controls (U+0000–U+001F) → Unicode Control Pictures (U+2400–U+241F) + # DEL (U+007F) → U+2421 SYMBOL FOR DELETE (␡) + # anything else → U+FFFD REPLACEMENT CHARACTER (?) + my $visible = + $char_ord <= 0x1F ? chr( $char_ord + 0x2400 ) + : $char_ord == 0x7F ? "\x{2421}" + : "\x{FFFD}"; + + my $last = $#{$chars_ref}; + my $win = 30; my $pre_start = ( $pos_0 > $win ) ? $pos_0 - $win : 0; my $post_end = ( $pos_0 + $win < $last ) ? $pos_0 + $win : $last; @@ -425,7 +434,7 @@ sub _context_snippet { my $suffix = ( $pos_0 + $win < $last ) ? '...' : ''; my $indent = ' '; - my $line = "$indent$prefix$pre$marker$post$suffix"; + my $line = "$indent$prefix$pre$visible$post$suffix"; my $caret_col = length($indent) + length($prefix) + length($pre); return "$line\n" . ( ' ' x $caret_col ) . '^'; -- 2.53.0