Given a PDF page, find plausible table structures. Largely borrowed from Anssi Nurminen's master's thesis: http://dspace.cc.tut.fi/dpub/bitstream/handle/123456789/21520/Nurminen.pdf?sequence=3 ... and inspired by Tabula: https://github.com/tabulapdf/tabula-extractor/issues/16
| 2023 | |
| 2024 | |
| 2025 | class TableFinder: |
| 2026 | """ |
| 2027 | Given a PDF page, find plausible table structures. |
| 2028 | |
| 2029 | Largely borrowed from Anssi Nurminen's master's thesis: |
| 2030 | http://dspace.cc.tut.fi/dpub/bitstream/handle/123456789/21520/Nurminen.pdf?sequence=3 |
| 2031 | |
| 2032 | ... and inspired by Tabula: |
| 2033 | https://github.com/tabulapdf/tabula-extractor/issues/16 |
| 2034 | """ |
| 2035 | |
| 2036 | def __init__(self, page, settings=None): |
| 2037 | self.page = weakref.proxy(page) |
| 2038 | self.textpage = None |
| 2039 | self.settings = TableSettings.resolve(settings) |
| 2040 | self.edges = self.get_edges() |
| 2041 | self.intersections = edges_to_intersections( |
| 2042 | self.edges, |
| 2043 | self.settings.intersection_x_tolerance, |
| 2044 | self.settings.intersection_y_tolerance, |
| 2045 | ) |
| 2046 | self.cells = intersections_to_cells(self.intersections) |
| 2047 | self.tables = [ |
| 2048 | Table(self.page, cell_group) |
| 2049 | for cell_group in cells_to_tables(self.page, self.cells) |
| 2050 | ] |
| 2051 | |
| 2052 | def get_edges(self) -> list: |
| 2053 | settings = self.settings |
| 2054 | |
| 2055 | for orientation in ["vertical", "horizontal"]: |
| 2056 | strategy = getattr(settings, orientation + "_strategy") |
| 2057 | if strategy == "explicit": |
| 2058 | lines = getattr(settings, "explicit_" + orientation + "_lines") |
| 2059 | if len(lines) < 2: |
| 2060 | raise ValueError( |
| 2061 | f"If {orientation}_strategy == 'explicit', " |
| 2062 | f"explicit_{orientation}_lines " |
| 2063 | f"must be specified as a list/tuple of two or more " |
| 2064 | f"floats/ints." |
| 2065 | ) |
| 2066 | |
| 2067 | v_strat = settings.vertical_strategy |
| 2068 | h_strat = settings.horizontal_strategy |
| 2069 | |
| 2070 | if v_strat == "text" or h_strat == "text": |
| 2071 | words = extract_words(CHARS, **(settings.text_settings or {})) |
| 2072 | else: |
| 2073 | words = [] |
| 2074 | |
| 2075 | v_explicit = [] |
| 2076 | for desc in settings.explicit_vertical_lines or []: |
| 2077 | if isinstance(desc, dict): |
| 2078 | for e in obj_to_edges(desc): |
| 2079 | if e["orientation"] == "v": |
| 2080 | v_explicit.append(e) |
| 2081 | else: |
| 2082 | v_explicit.append( |
no outgoing calls
no test coverage detected
searching dependent graphs…