File Coverage

blib/lib/Text/LineNumber.pm
Criterion Covered Total %
statement 6 28 21.4
branch 0 10 0.0
condition 0 3 0.0
subroutine 2 5 40.0
pod 3 3 100.0
total 11 49 22.4


line stmt bran cond sub pod time code
1             #
2             # LineNumber.pm
3             #
4             # Copyright (c) 2008, Juergen Weigert, Novell Inc.
5             # This module is free software. It may be used, redistributed
6             # and/or modified under the same terms as Perl (version 5.8.8) itself.
7             #
8              
9             package Text::LineNumber;
10              
11 1     1   43398 use warnings;
  1         3  
  1         28  
12 1     1   5 use strict;
  1         2  
  1         341  
13              
14             =head1 NAME
15              
16             Text::LineNumber - Convert between offsets and line numbers.
17              
18             =head1 VERSION
19              
20             Version 0.02
21              
22             =cut
23              
24             our $VERSION = '0.02';
25              
26              
27             =head1 SYNOPSIS
28              
29             This module creates a conversion object for the given text.
30             The object features two lookup methods that convert forward or backward.
31              
32             use Text::LineNumber;
33              
34             my $text = "foo\nHello World\r\nbar\rbaz";
35             my $tln = Text::LineNumber->new($text);
36             my $world_lnr = $tln->off2lnr(10); # = 2
37             my @world = $tln->off2lnr(10); # = (2, 7)
38             my $l3o = $tln->lnr2off(3); # = 17
39             my $line3 = substr $text, $l3o, $tln->lnr2off(4)-$l3o; # = "bar\r"
40              
41             All three line ending styles (Unix, Mac, Windows) are recognized as line breaks.
42             The offset of the first character in the text is 0.
43             the number of the first line is 1.
44             The column of the first character in a line is 1.
45            
46              
47             =head1 METHODS
48              
49             =head2 new($text)
50              
51             New reads the entire text and creates an object containing sufficient metadata.
52             Later changes of $text have no effect on the methods of this object.
53             =cut
54              
55             sub new
56             {
57 0     0 1   my ($self, $text) = @_;
58 0   0       my $class = ref($self) || $self;
59 0           my $lnr_off = [ 0 ];
60 0           while ($text =~ m{(\r\n|\n|\r)}gs)
61             {
62             # pos() returns the offset of the next character
63             # after the match -- exactly what we need here.
64 0           push @$lnr_off, pos $text;
65             }
66 0           return bless $lnr_off, $class;
67             }
68              
69              
70             =head2 off2lnr($offset)
71              
72             Off2lnr converts a byte offset to a line number.
73             If called in an array context it returns line number and column number.
74             A binary search is used for the line that contains the given offset.
75              
76             =cut
77              
78             ## the first line has lnr 1,
79             ## the first byte in a line has column 1.
80             sub off2lnr
81             {
82 0     0 1   my ($self, $offset) = @_;
83 0           my $l = 0;
84 0           my $h = $#$self;
85 0           while ($h - $l > 1)
86             {
87 0           my $n = ($l + $h) >> 1;
88 0 0         if ($self->[$n] <= $offset)
89             {
90 0           $l = $n;
91 0 0         $h = $n if $self->[$l] == $offset;
92             }
93             else
94             {
95 0           $h = $n;
96             }
97             }
98            
99 0 0         return $h unless wantarray;
100 0           return ($h, $offset - $self->[$l] + 1);
101             }
102              
103              
104             =head2 lnr2off($line)
105              
106             Lnr2off converts a line number to a byte offset.
107             The offset of the first character of a line is returned.
108             the first character is the one immediatly following the
109             previous line ending.
110              
111             Returns 0 when called with 0 or negative parameters.
112             Returns the offset of the last line when called with
113             too high a line number.
114             =cut
115              
116              
117             ## the first byte has offset 0
118             sub lnr2off
119             {
120 0     0 1   my ($self, $lnr) = @_;
121 0 0         return 0 if $lnr <= 0;
122 0           my $off = $self->[$lnr-1];
123 0 0         return $self->[-1] unless defined $off;
124 0           return $off;
125             }
126              
127              
128             =head1 AUTHOR
129              
130             Juergen Weigert, C<< >>
131              
132             =head1 BUGS
133              
134             - The implementation is quite trivial and uses a straight forward binary search.
135              
136             - Learning how to use this module may be more effort than writing something
137             similar yourself. Using this module still saves you some headache about
138             off-by-one errors.
139              
140              
141             Please report any bugs or feature requests to C, or through
142             the web interface at L. I will be notified, and then you'll
143             automatically be notified of progress on your bug as I make changes.
144              
145              
146              
147              
148             =head1 SUPPORT
149              
150             You can find documentation for this module with the perldoc command.
151              
152             perldoc Text::LineNumber
153              
154              
155             You can also look for information at:
156              
157             =over 4
158              
159             =item * RT: CPAN's request tracker
160              
161             L
162              
163             =item * AnnoCPAN: Annotated CPAN documentation
164              
165             L
166              
167             =item * CPAN Ratings
168              
169             L
170              
171             =item * Search CPAN
172              
173             L
174              
175             =back
176              
177              
178             =head1 ACKNOWLEDGEMENTS
179              
180              
181             =head1 COPYRIGHT & LICENSE
182              
183             Copyright 2008 Juergen Weigert, all rights reserved.
184              
185             This program is free software; you can redistribute it and/or modify it
186             under the same terms as Perl itself.
187              
188              
189             =cut
190              
191             1; # End of Text::LineNumber