|
2 | 2 | from abc import ABC, abstractmethod |
3 | 3 | from collections import ChainMap, defaultdict |
4 | 4 | from contextlib import contextmanager |
| 5 | +from itertools import pairwise |
5 | 6 | from typing import Any, Callable, ClassVar, Iterator, Pattern, cast |
6 | 7 |
|
7 | 8 | from typing_extensions import Self |
@@ -1717,15 +1718,11 @@ def escape_and_quote_field(self, field_name: str) -> str: |
1717 | 1718 | match_positions.update((match.start() for match in re_quote.finditer(field_name))) |
1718 | 1719 |
|
1719 | 1720 | if len(match_positions) > 0: # found matches, escape them |
1720 | | - r = [0] + list(sorted(match_positions)) + [len(field_name)] |
1721 | | - escaped_field_name = "" |
1722 | | - for i in range( |
1723 | | - len(r) - 1 |
1724 | | - ): # TODO: from Python 3.10 this can be replaced with itertools.pairwise(), but for now we keep support for Python <3.10 |
1725 | | - if i == 0: # The first range is passed to the result without escaping |
1726 | | - escaped_field_name += field_name[r[i] : r[i + 1]] |
1727 | | - else: # Subsequent ranges are positions of matches and therefore are prepended with field_escape |
1728 | | - escaped_field_name += self.field_escape + field_name[r[i] : r[i + 1]] |
| 1721 | + indices = [0, *sorted(match_positions), len(field_name)] |
| 1722 | + escaped_field_name = self.field_escape.join( |
| 1723 | + field_name[first_index:second_index] |
| 1724 | + for (first_index, second_index) in pairwise(indices) |
| 1725 | + ) |
1729 | 1726 | else: # no matches, just pass original field name without escaping |
1730 | 1727 | escaped_field_name = field_name |
1731 | 1728 | else: |
|
0 commit comments