Class: PdfTableExtractorRow
- Inherits:
-
Object
- Object
- PdfTableExtractorRow
- Defined in:
- lib/pdf_table_extractor/pdf_table_extractor_row.rb
Overview
Represents a parsed row of cells with positions and supports merging/grouping.
Instance Attribute Summary collapse
-
#cells ⇒ Array<Hash>
readonly
Cells with :text and :position.
-
#index ⇒ Integer?
readonly
Original index when parsed (nil for merged rows).
-
#merged ⇒ Boolean
readonly
Whether this row is a merged row (not original).
-
#positions ⇒ Array<Integer>
readonly
Positions of the cells in this row.
Instance Method Summary collapse
-
#congruent_with_last_merged? ⇒ Boolean
Whether positions are congruent with last merged row.
-
#congruent_with_previous? ⇒ Boolean
Whether positions are congruent with previous row.
-
#incongruent_with_neighbours? ⇒ Boolean
Whether this row is incongruent relative to neighbours.
-
#initialize(extractor, cells, positions, index, merged = false) ⇒ PdfTableExtractorRow
constructor
A new instance of PdfTableExtractorRow.
-
#merge!(row) ⇒ void
Merge text into matching cell positions from another row.
-
#nxt ⇒ PdfTableExtractorRow?
Next row in extractor.
-
#positions_match_with?(other_row) ⇒ Boolean
Check if positions match with another row (within tolerance).
-
#prev ⇒ PdfTableExtractorRow?
Previous row in extractor.
-
#single_cell?(against = :previous) ⇒ Boolean
Whether this row is a single-cell row at position 0.
-
#transform_to_single_cell! ⇒ void
Transform this row into a single-cell row by merging text.
Constructor Details
#initialize(extractor, cells, positions, index, merged = false) ⇒ PdfTableExtractorRow
Returns a new instance of PdfTableExtractorRow.
16 17 18 19 20 21 22 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 16 def initialize(extractor, cells, positions, index, merged = false) @extractor = extractor @cells = cells @index = index @merged = merged @positions = positions end |
Instance Attribute Details
#cells ⇒ Array<Hash> (readonly)
Returns cells with :text and :position.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 13 class PdfTableExtractorRow attr_reader :positions, :index, :cells, :merged def initialize(extractor, cells, positions, index, merged = false) @extractor = extractor @cells = cells @index = index @merged = merged @positions = positions end # Whether this row is a single-cell row at position 0. # @param against [Symbol] :previous or :last_merged # @return [Boolean] def single_cell?(against = :previous) other_row = (against == :previous) ? prev : last_merged unless @merged second_pos = other_row&.positions&.[](1).to_i @positions == [0] && ( @merged || @index == 0 || other_row.single_cell? || @cells.first[:text].length > second_pos - 2 ) end # Previous row in extractor. # @return [PdfTableExtractorRow, nil] def prev return nil if @index.zero? @extractor.rows[@index - 1] end # Next row in extractor. # @return [PdfTableExtractorRow, nil] def nxt return nil if @index == @extractor.rows.length - 1 @extractor.rows[@index + 1] end # @return [Boolean] whether positions are congruent with previous row def congruent_with_previous? single_cell? == prev&.single_cell? && positions_match_with?(prev) end # @return [Boolean] whether positions are congruent with last merged row def congruent_with_last_merged? single_cell?(:last_merged) == last_merged&.single_cell? && positions_match_with?(last_merged) end # @return [Boolean] whether this row is incongruent relative to neighbours def incongruent_with_neighbours? !single_cell? && !(prev && congruent_with_previous?) && !nxt&.congruent_with_previous? end # Check if positions match with another row (within tolerance). # @param other_row [PdfTableExtractorRow, nil] # @return [Boolean] def positions_match_with?(other_row) @positions.each do |pos| if @extractor.[:position_tolerance].zero? return false unless other_row&.positions.to_a.include?(pos) elsif ([pos..pos + @extractor.[:position_tolerance]] - other_row&.positions.to_a).length == @extractor.[:position_tolerance] + 1 return false end end true end # Transform this row into a single-cell row by merging text. # @return [void] def transform_to_single_cell! @cells = [{ text: @cells.sort_by { |c| c[:position] }.map { |c| c[:text] }.join(" ").gsub(/\s+/, " ").strip, position: 0 }] @positions = [0] end # Merge text into matching cell positions from another row. # @param row [PdfTableExtractorRow] # @return [void] def merge!(row) @cells.each do |cell| r_cell = row.cells.find { |c| c[:position] == cell[:position] } cell[:text] += "\s#{r_cell[:text]}" if r_cell end end private # @return [PdfTableExtractorRow, nil] def last_merged @extractor.merged_rows.last end end |
#index ⇒ Integer? (readonly)
Returns original index when parsed (nil for merged rows).
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 13 class PdfTableExtractorRow attr_reader :positions, :index, :cells, :merged def initialize(extractor, cells, positions, index, merged = false) @extractor = extractor @cells = cells @index = index @merged = merged @positions = positions end # Whether this row is a single-cell row at position 0. # @param against [Symbol] :previous or :last_merged # @return [Boolean] def single_cell?(against = :previous) other_row = (against == :previous) ? prev : last_merged unless @merged second_pos = other_row&.positions&.[](1).to_i @positions == [0] && ( @merged || @index == 0 || other_row.single_cell? || @cells.first[:text].length > second_pos - 2 ) end # Previous row in extractor. # @return [PdfTableExtractorRow, nil] def prev return nil if @index.zero? @extractor.rows[@index - 1] end # Next row in extractor. # @return [PdfTableExtractorRow, nil] def nxt return nil if @index == @extractor.rows.length - 1 @extractor.rows[@index + 1] end # @return [Boolean] whether positions are congruent with previous row def congruent_with_previous? single_cell? == prev&.single_cell? && positions_match_with?(prev) end # @return [Boolean] whether positions are congruent with last merged row def congruent_with_last_merged? single_cell?(:last_merged) == last_merged&.single_cell? && positions_match_with?(last_merged) end # @return [Boolean] whether this row is incongruent relative to neighbours def incongruent_with_neighbours? !single_cell? && !(prev && congruent_with_previous?) && !nxt&.congruent_with_previous? end # Check if positions match with another row (within tolerance). # @param other_row [PdfTableExtractorRow, nil] # @return [Boolean] def positions_match_with?(other_row) @positions.each do |pos| if @extractor.[:position_tolerance].zero? return false unless other_row&.positions.to_a.include?(pos) elsif ([pos..pos + @extractor.[:position_tolerance]] - other_row&.positions.to_a).length == @extractor.[:position_tolerance] + 1 return false end end true end # Transform this row into a single-cell row by merging text. # @return [void] def transform_to_single_cell! @cells = [{ text: @cells.sort_by { |c| c[:position] }.map { |c| c[:text] }.join(" ").gsub(/\s+/, " ").strip, position: 0 }] @positions = [0] end # Merge text into matching cell positions from another row. # @param row [PdfTableExtractorRow] # @return [void] def merge!(row) @cells.each do |cell| r_cell = row.cells.find { |c| c[:position] == cell[:position] } cell[:text] += "\s#{r_cell[:text]}" if r_cell end end private # @return [PdfTableExtractorRow, nil] def last_merged @extractor.merged_rows.last end end |
#merged ⇒ Boolean (readonly)
Returns whether this row is a merged row (not original).
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 13 class PdfTableExtractorRow attr_reader :positions, :index, :cells, :merged def initialize(extractor, cells, positions, index, merged = false) @extractor = extractor @cells = cells @index = index @merged = merged @positions = positions end # Whether this row is a single-cell row at position 0. # @param against [Symbol] :previous or :last_merged # @return [Boolean] def single_cell?(against = :previous) other_row = (against == :previous) ? prev : last_merged unless @merged second_pos = other_row&.positions&.[](1).to_i @positions == [0] && ( @merged || @index == 0 || other_row.single_cell? || @cells.first[:text].length > second_pos - 2 ) end # Previous row in extractor. # @return [PdfTableExtractorRow, nil] def prev return nil if @index.zero? @extractor.rows[@index - 1] end # Next row in extractor. # @return [PdfTableExtractorRow, nil] def nxt return nil if @index == @extractor.rows.length - 1 @extractor.rows[@index + 1] end # @return [Boolean] whether positions are congruent with previous row def congruent_with_previous? single_cell? == prev&.single_cell? && positions_match_with?(prev) end # @return [Boolean] whether positions are congruent with last merged row def congruent_with_last_merged? single_cell?(:last_merged) == last_merged&.single_cell? && positions_match_with?(last_merged) end # @return [Boolean] whether this row is incongruent relative to neighbours def incongruent_with_neighbours? !single_cell? && !(prev && congruent_with_previous?) && !nxt&.congruent_with_previous? end # Check if positions match with another row (within tolerance). # @param other_row [PdfTableExtractorRow, nil] # @return [Boolean] def positions_match_with?(other_row) @positions.each do |pos| if @extractor.[:position_tolerance].zero? return false unless other_row&.positions.to_a.include?(pos) elsif ([pos..pos + @extractor.[:position_tolerance]] - other_row&.positions.to_a).length == @extractor.[:position_tolerance] + 1 return false end end true end # Transform this row into a single-cell row by merging text. # @return [void] def transform_to_single_cell! @cells = [{ text: @cells.sort_by { |c| c[:position] }.map { |c| c[:text] }.join(" ").gsub(/\s+/, " ").strip, position: 0 }] @positions = [0] end # Merge text into matching cell positions from another row. # @param row [PdfTableExtractorRow] # @return [void] def merge!(row) @cells.each do |cell| r_cell = row.cells.find { |c| c[:position] == cell[:position] } cell[:text] += "\s#{r_cell[:text]}" if r_cell end end private # @return [PdfTableExtractorRow, nil] def last_merged @extractor.merged_rows.last end end |
#positions ⇒ Array<Integer> (readonly)
Returns positions of the cells in this row.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 13 class PdfTableExtractorRow attr_reader :positions, :index, :cells, :merged def initialize(extractor, cells, positions, index, merged = false) @extractor = extractor @cells = cells @index = index @merged = merged @positions = positions end # Whether this row is a single-cell row at position 0. # @param against [Symbol] :previous or :last_merged # @return [Boolean] def single_cell?(against = :previous) other_row = (against == :previous) ? prev : last_merged unless @merged second_pos = other_row&.positions&.[](1).to_i @positions == [0] && ( @merged || @index == 0 || other_row.single_cell? || @cells.first[:text].length > second_pos - 2 ) end # Previous row in extractor. # @return [PdfTableExtractorRow, nil] def prev return nil if @index.zero? @extractor.rows[@index - 1] end # Next row in extractor. # @return [PdfTableExtractorRow, nil] def nxt return nil if @index == @extractor.rows.length - 1 @extractor.rows[@index + 1] end # @return [Boolean] whether positions are congruent with previous row def congruent_with_previous? single_cell? == prev&.single_cell? && positions_match_with?(prev) end # @return [Boolean] whether positions are congruent with last merged row def congruent_with_last_merged? single_cell?(:last_merged) == last_merged&.single_cell? && positions_match_with?(last_merged) end # @return [Boolean] whether this row is incongruent relative to neighbours def incongruent_with_neighbours? !single_cell? && !(prev && congruent_with_previous?) && !nxt&.congruent_with_previous? end # Check if positions match with another row (within tolerance). # @param other_row [PdfTableExtractorRow, nil] # @return [Boolean] def positions_match_with?(other_row) @positions.each do |pos| if @extractor.[:position_tolerance].zero? return false unless other_row&.positions.to_a.include?(pos) elsif ([pos..pos + @extractor.[:position_tolerance]] - other_row&.positions.to_a).length == @extractor.[:position_tolerance] + 1 return false end end true end # Transform this row into a single-cell row by merging text. # @return [void] def transform_to_single_cell! @cells = [{ text: @cells.sort_by { |c| c[:position] }.map { |c| c[:text] }.join(" ").gsub(/\s+/, " ").strip, position: 0 }] @positions = [0] end # Merge text into matching cell positions from another row. # @param row [PdfTableExtractorRow] # @return [void] def merge!(row) @cells.each do |cell| r_cell = row.cells.find { |c| c[:position] == cell[:position] } cell[:text] += "\s#{r_cell[:text]}" if r_cell end end private # @return [PdfTableExtractorRow, nil] def last_merged @extractor.merged_rows.last end end |
Instance Method Details
#congruent_with_last_merged? ⇒ Boolean
Returns whether positions are congruent with last merged row.
57 58 59 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 57 def congruent_with_last_merged? single_cell?(:last_merged) == last_merged&.single_cell? && positions_match_with?(last_merged) end |
#congruent_with_previous? ⇒ Boolean
Returns whether positions are congruent with previous row.
52 53 54 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 52 def congruent_with_previous? single_cell? == prev&.single_cell? && positions_match_with?(prev) end |
#incongruent_with_neighbours? ⇒ Boolean
Returns whether this row is incongruent relative to neighbours.
62 63 64 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 62 def incongruent_with_neighbours? !single_cell? && !(prev && congruent_with_previous?) && !nxt&.congruent_with_previous? end |
#merge!(row) ⇒ void
This method returns an undefined value.
Merge text into matching cell positions from another row.
93 94 95 96 97 98 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 93 def merge!(row) @cells.each do |cell| r_cell = row.cells.find { |c| c[:position] == cell[:position] } cell[:text] += "\s#{r_cell[:text]}" if r_cell end end |
#nxt ⇒ PdfTableExtractorRow?
Next row in extractor.
45 46 47 48 49 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 45 def nxt return nil if @index == @extractor.rows.length - 1 @extractor.rows[@index + 1] end |
#positions_match_with?(other_row) ⇒ Boolean
Check if positions match with another row (within tolerance).
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 69 def positions_match_with?(other_row) @positions.each do |pos| if @extractor.[:position_tolerance].zero? return false unless other_row&.positions.to_a.include?(pos) elsif ([pos..pos + @extractor.[:position_tolerance]] - other_row&.positions.to_a).length == @extractor.[:position_tolerance] + 1 return false end end true end |
#prev ⇒ PdfTableExtractorRow?
Previous row in extractor.
37 38 39 40 41 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 37 def prev return nil if @index.zero? @extractor.rows[@index - 1] end |
#single_cell?(against = :previous) ⇒ Boolean
Whether this row is a single-cell row at position 0.
27 28 29 30 31 32 33 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 27 def single_cell?(against = :previous) other_row = (against == :previous) ? prev : last_merged unless @merged second_pos = other_row&.positions&.[](1).to_i @positions == [0] && ( @merged || @index == 0 || other_row.single_cell? || @cells.first[:text].length > second_pos - 2 ) end |
#transform_to_single_cell! ⇒ void
This method returns an undefined value.
Transform this row into a single-cell row by merging text.
82 83 84 85 86 87 88 |
# File 'lib/pdf_table_extractor/pdf_table_extractor_row.rb', line 82 def transform_to_single_cell! @cells = [{ text: @cells.sort_by { |c| c[:position] }.map { |c| c[:text] }.join(" ").gsub(/\s+/, " ").strip, position: 0 }] @positions = [0] end |