feat: add spans
This commit is contained in:
@@ -40,3 +40,12 @@ class AccessType(Enum):
|
||||
MUTUAL = 'mutual' # взаимные
|
||||
FOLLOWERS = 'followers' # подписчики
|
||||
EVERYONE = 'everyone' # все
|
||||
|
||||
class SpanType(Enum):
|
||||
MONOSPACE = 'monospace' # моноширный (код)
|
||||
STRIKE = 'strike' # зачеркнутый
|
||||
BOLD = 'bold' # жирный
|
||||
ITALIC = 'italic' # курсив
|
||||
SPOILER = 'spoiler' # спойлер
|
||||
UNDERLINE = 'underline' # подчеркнутый
|
||||
HASHTAG = 'hashtag' # хэштэг ? (появляется только при получении постов, при создании нету)
|
||||
|
||||
@@ -7,6 +7,7 @@ from itd.models.user import UserPost, UserNewPost
|
||||
from itd.models._text import TextObject
|
||||
from itd.models.file import PostAttach
|
||||
from itd.models.comment import Comment
|
||||
from itd.enums import SpanType
|
||||
|
||||
|
||||
class NewPollOption(BaseModel):
|
||||
|
||||
@@ -39,7 +39,7 @@ def fetch(token: str, method: str, url: str, params: dict = {}, files: dict[str,
|
||||
raise RateLimitExceeded(res.json()['error'].get('retryAfter', 0))
|
||||
if res.json().get('error', {}).get('code') == 'UNAUTHORIZED':
|
||||
raise Unauthorized()
|
||||
if res.json().get('error', {}).get('code') == 'ACCOUNT_BANNED':
|
||||
if res.json().get('error', {}).get('code') in ('ACCOUNT_BANNED', 'USER_BLOCKED'):
|
||||
raise AccountBanned()
|
||||
if res.json().get('error', {}).get('code') == 'PROFILE_REQUIRED':
|
||||
raise ProfileRequired()
|
||||
|
||||
114
itd/utils.py
Normal file
114
itd/utils.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# новая версия от чат гпт. у меня самого не получилось сделать
|
||||
from itd.models.post import Span
|
||||
from itd.enums import SpanType
|
||||
|
||||
|
||||
class Tag:
|
||||
def __init__(self, open: str, close: str, type: SpanType):
|
||||
self.open = open
|
||||
self.close = close
|
||||
self.type = type
|
||||
|
||||
|
||||
def _parse_spans(text: str, tags: list[Tag]) -> tuple[str, list[Span]]:
|
||||
spans: list[Span] = []
|
||||
stack: list[tuple[int, SpanType, int, int]] = []
|
||||
clean_chars: list[str] = []
|
||||
i = 0
|
||||
|
||||
while i < len(text):
|
||||
closed = False
|
||||
for idx, tag in enumerate(tags):
|
||||
if text.startswith(tag.close, i) and stack and stack[-1][0] == idx:
|
||||
_, span_type, offset, _ = stack.pop()
|
||||
spans.append(Span(length=len(clean_chars) - offset, offset=offset, type=span_type))
|
||||
i += len(tag.close)
|
||||
closed = True
|
||||
break
|
||||
if closed:
|
||||
continue
|
||||
|
||||
opened = False
|
||||
for idx, tag in enumerate(tags):
|
||||
if text.startswith(tag.open, i):
|
||||
stack.append((idx, tag.type, len(clean_chars), i))
|
||||
i += len(tag.open)
|
||||
opened = True
|
||||
break
|
||||
if opened:
|
||||
continue
|
||||
|
||||
clean_chars.append(text[i])
|
||||
i += 1
|
||||
|
||||
if stack:
|
||||
_, last_type, _, raw_pos = stack[-1]
|
||||
raise ValueError(f'No closing tag for {last_type.value} at pos {raw_pos}')
|
||||
|
||||
spans.sort(key=lambda span: span.offset)
|
||||
return ''.join(clean_chars), spans
|
||||
|
||||
|
||||
def parse_html(text: str) -> tuple[str, list[Span]]:
|
||||
return _parse_spans(
|
||||
text,
|
||||
[
|
||||
Tag('<b>', '</b>', SpanType.BOLD),
|
||||
Tag('<i>', '</i>', SpanType.ITALIC),
|
||||
Tag('<s>', '</s>', SpanType.STRIKE),
|
||||
Tag('<u>', '</u>', SpanType.UNDERLINE),
|
||||
Tag('<code>', '</code>', SpanType.MONOSPACE),
|
||||
Tag('<spoiler>', '</spoiler>', SpanType.SPOILER),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
# версия от человека (не работает с вложенными тэгами)
|
||||
# from re import finditer, Match
|
||||
|
||||
# from itd.models.post import Span
|
||||
# from itd.enums import SpanType
|
||||
|
||||
|
||||
# class Tag:
|
||||
# def __init__(self, open: str, close: str, type: SpanType):
|
||||
# self.open = open
|
||||
# self.close = close
|
||||
# self.type = type
|
||||
|
||||
# def raise_error(self, pos: int):
|
||||
# raise ValueError(f'No closing tag for {self.type.value} at pos {pos - len(self.open)}')
|
||||
|
||||
# def to_span(self, start: int, end: int) -> Span:
|
||||
# return Span(length=end - (start - len(self.open)), offset=start - len(self.open), type=self.type)
|
||||
|
||||
# def get_pos(self, match: Match[str], text: str, offset: int) -> tuple[int, int, str]:
|
||||
# start = match.end() - offset
|
||||
# text = text[:match.start() - offset] + text[start:]
|
||||
# end = text.find(self.close, start)
|
||||
# if end == -1:
|
||||
# self.raise_error(start)
|
||||
|
||||
# return start - len(self.open), end, text[:end] + text[end + len(self.close):]
|
||||
|
||||
|
||||
# def parse_html(text: str) -> tuple[str, list[Span]]:
|
||||
# spans = []
|
||||
|
||||
# for tag in [
|
||||
# Tag('<b>', '</b>', SpanType.BOLD),
|
||||
# Tag('<i>', '</i>', SpanType.ITALIC),
|
||||
# Tag('<s>', '</s>', SpanType.STRIKE),
|
||||
# Tag('<u>', '</u>', SpanType.UNDERLINE),
|
||||
# Tag('<code>', '</code>', SpanType.MONOSPACE),
|
||||
# Tag('<spoiler>', '</spoiler>', SpanType.SPOILER),
|
||||
# ]:
|
||||
|
||||
# offset = 0
|
||||
# full_text = text
|
||||
# for match in finditer(tag.open, full_text):
|
||||
# start, end, text = tag.get_pos(match, text, offset)
|
||||
# spans.append(tag.to_span(start, end))
|
||||
# offset += len(tag.open) + len(tag.close)
|
||||
|
||||
# return text, spans
|
||||
Reference in New Issue
Block a user