1use strict; use warnings; 2 3package Text::Tabs; 4 5BEGIN { require Exporter; *import = \&Exporter::import } 6 7our @EXPORT = qw( expand unexpand $tabstop ); 8 9our $VERSION = '2024.001'; 10our $SUBVERSION = 'modern'; # back-compat vestige 11 12our $tabstop = 8; 13 14sub expand { 15 my @l; 16 my $pad; 17 for ( @_ ) { 18 defined or do { push @l, ''; next }; 19 my $s = ''; 20 for (split(/^/m, $_, -1)) { 21 my $offs; 22 for (split(/\t/, $_, -1)) { 23 if (defined $offs) { 24 $pad = $tabstop - $offs % $tabstop; 25 $s .= " " x $pad; 26 } 27 $s .= $_; 28 $offs = /^\pM/ + ( () = /\PM/g ); 29 } 30 } 31 push(@l, $s); 32 } 33 return @l if wantarray; 34 return $l[0]; 35} 36 37sub unexpand 38{ 39 my (@l) = @_; 40 my @e; 41 my $x; 42 my $line; 43 my @lines; 44 my $lastbit; 45 my $ts_as_space = " " x $tabstop; 46 for $x (@l) { 47 defined $x or next; 48 @lines = split("\n", $x, -1); 49 for $line (@lines) { 50 $line = expand($line); 51 @e = split(/((?:\PM\pM*|^\pM+){$tabstop})/,$line,-1); 52 $lastbit = pop(@e); 53 $lastbit = '' 54 unless defined $lastbit; 55 $lastbit = "\t" 56 if $lastbit eq $ts_as_space; 57 for $_ (@e) { 58 s/ +$/\t/; 59 } 60 $line = join('',@e, $lastbit); 61 } 62 $x = join("\n", @lines); 63 } 64 return @l if wantarray; 65 return $l[0]; 66} 67 681; 69 70__END__ 71 72=head1 NAME 73 74Text::Tabs - expand and unexpand tabs like unix expand(1) and unexpand(1) 75 76=head1 SYNOPSIS 77 78 use Text::Tabs; 79 80 $tabstop = 4; # default = 8 81 @lines_without_tabs = expand(@lines_with_tabs); 82 @lines_with_tabs = unexpand(@lines_without_tabs); 83 84=head1 DESCRIPTION 85 86Text::Tabs does most of what the unix utilities expand(1) and unexpand(1) 87do. Given a line with tabs in it, C<expand> replaces those tabs with 88the appropriate number of spaces. Given a line with or without tabs in 89it, C<unexpand> adds tabs when it can save bytes by doing so, 90like the C<unexpand -a> command. 91 92Unlike the old unix utilities, this module correctly accounts for 93any Unicode combining characters (such as diacriticals) that may occur 94in each line for both expansion and unexpansion. These are overstrike 95characters that do not increment the logical position. Make sure 96you have the appropriate Unicode settings enabled. 97 98=head1 EXPORTS 99 100The following are exported: 101 102=over 4 103 104=item expand 105 106=item unexpand 107 108=item $tabstop 109 110The C<$tabstop> variable controls how many column positions apart each 111tabstop is. The default is 8. 112 113Please note that C<local($tabstop)> doesn't do the right thing and if you want 114to use C<local> to override C<$tabstop>, you need to use 115C<local($Text::Tabs::tabstop)>. 116 117=back 118 119=head1 EXAMPLE 120 121 #!perl 122 # unexpand -a 123 use Text::Tabs; 124 125 while (<>) { 126 print unexpand $_; 127 } 128 129Instead of the shell's C<expand> command, use: 130 131 perl -MText::Tabs -n -e 'print expand $_' 132 133Instead of the shell's C<unexpand -a> command, use: 134 135 perl -MText::Tabs -n -e 'print unexpand $_' 136 137=head1 BUGS 138 139Text::Tabs handles only tabs (C<"\t">) and combining characters (C</\pM/>). It doesn't 140count backwards for backspaces (C<"\t">), omit other non-printing control characters (C</\pC/>), 141or otherwise deal with any other zero-, half-, and full-width characters. 142 143=head1 LICENSE 144 145Copyright (C) 1996-2002,2005,2006 David Muir Sharnoff. 146Copyright (C) 2005 Aristotle Pagaltzis 147Copyright (C) 2012-2013 Google, Inc. 148This module may be modified, used, copied, and redistributed at your own risk. 149Although allowed by the preceding license, please do not publicly 150redistribute modified versions of this code with the name "Text::Tabs" 151unless it passes the unmodified Text::Tabs test suite. 152