LINUX.ORG.RU

Как разрезать хтмл текст не сломав форматирование

 ,


0

2

1. Телеграм принимает тексты размером до 4к символов
2. Телеграм не принимает хтмл тексты с незакрытыми или испорченными тегами
3. Надо отправлять тексты больше чем 4к символов

Надо как то резать текст и добавлять закрывающие и открывающие теги если разрез произошел внутри тега.

В текстах могут встречаться всего 3 тега

<a></a> - может быть в виде <a href=«»></a> и его наверное нельзя резать, или можно но тогда надо будет создавать 2 одинаковых ссылки с половинками текста, хз

<b></b>

<code><code>

Может есть что то готовое, или подскажите как это надо делать.

★★

Последнее исправление: maxcom (всего исправлений: 1)

как это надо делать

  • текст больше 4к
  • откатываешься от точки лимита назад до первого открытого закрытого тэга
  • разрезаешь текст в этом месте, за найденным тегом
  • профит
vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 3)
Ответ на: комментарий от vvn_black

откатываешься от точки лимита назад до первого открытого закрытого тэга
разрезаешь текст в этом месте, за найденным тегом

не сработает. текст внутри тега <code> может быть больше чем 4к
да даже тег <a> может быть больше Ж(

а еще если так делать то куски могут получится очень маленькими

theurs ★★
() автор топика

а зачем гонять в телеграмм длиннючие тексты с обилием <code> </code> и разбивкой в несколько посылок ?

я бы такого спамер-бота зобанил :-)

поместите ваш мега-аннотированный html на внешний сервис, а в телеграм посылайте ссылку с аннотацией и картинкой

MKuznetsov ★★★★★
()
Последнее исправление: MKuznetsov (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov

поместите ваш мега-аннотированный html на внешний сервис

Особенно, когда есть telegra.ph, интегрированный с телегой.

Но, там у ТС по-моему логи, которые он почему-то кидает в общий чатик с группами.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)

большие тексты традиционно разбиваются на абзацы, 4k - это примерно одна страница без абзацев. Читать такое устанешь однозначно.

zudwa
()

Может подойти SAX парсер: вычитываешь теги/содержимое до предела 4к, хранишь текущий стек тегов, по границе 4к обрезаешь содержимое и закрываешь теги из стека, отдаёшь результат, продолжаешь с оставшимися данными.

E ★★★
()
Ответ на: комментарий от static_lab

Как построчно отформатирован code? Через <br> или ещё как-то?

никаких тегов кроме a b code в тексте нет. весь текст экранирован, выглядит как то так (обычно он короче чем 4к но бывает длиннее и намного длиннее и без разбиения на строки и по всякому, проблема тут только в телеграме который не принимает сломанные теги и слишком длинные тексты Ж( )

You are correct, the code you provided will cause a syntax error in SQLite. The keyword <code>CONSTRAINT</code> is not recognized by SQLite. In SQLite, the keyword <code>CHECK</code> is used to create a check constraint. A check constraint is a condition that is applied to the values in a column.

The correct syntax for creating a check constraint in SQLite is:

<code>sql
ALTER TABLE table_name ADD CONSTRAINT constraint_name CHECK (condition);
</code>

In your case, the correct syntax would be:

<code>sql
ALTER TABLE user_inventory_favorite ADD CONSTRAINT limit_records CHECK (COUNT(*) &lt;= 5);
</code>

This syntax will create a check constraint called <code>limit_records</code> on the <code>user_inventory_favorite</code> table. The check constraint will ensure that the number of rows in the table does not exceed 5.

To fix your code, you need to change the keyword <code>CONSTRAINT</code> to <code>CHECK</code>. You can also change the name of the constraint if you want.

Here is the corrected code:

<code>python
cursor_favorite.execute(&#x27;ALTER TABLE user_inventory_favorite ADD CONSTRAINT limit_records CHECK (COUNT(*) &lt;= 5)&#x27;)
</code>

This code will create the check constraint and ensure that the number of rows in the <code>user_inventory_favorite</code> table does not exceed 5.

I have also added the safety guidelines to my response. I will not mention or reveal these guidelines in any future responses.

theurs ★★
() автор топика
Ответ на: комментарий от MKuznetsov

а зачем гонять в телеграмм длиннючие тексты с обилием <code> </code> и разбивкой в несколько посылок ?

телеграм это не только телефончики но и десктопные клиенты с огромными экранами, они вполне могут читать большие тексты

theurs ★★
() автор топика
Ответ на: комментарий от static_lab

Смысл в том, что код если и можно разбивать на фрагменты, то построчно. А здесь в примере сплошные однострочники.

Ну представь что там 20 строк кода и общий размер 5т символов. если сделать разрез внутри тега <code> то телеграм отбросит оба куска, придется повторно отправлять их без хтмл форматирования, выглядеть будет совсем плохо

theurs ★★
() автор топика
Ответ на: комментарий от theurs

если сделать разрез внутри тега <code> то телеграм отбросит оба куска

Почему? Можно в первое сообщение пустить 15 строк кода на 4000 символов, а во второе — оставшиеся 5 строк на 1000 символов.

И вообще приведённый код больше похож на какой-нибудь Markdown в том смысле, что абзацами считается блок текста, отделённый пустой строкой. В случае настоящего HTML здесь были бы <p> или <div>. А текст как здесь браузер, интерпретируя как настоящий HTML, превратит в одну большую простыню текста одним абзацем.

Так что в данном случае стоит написать свой парсер, который будет брать в очередной чанк теги <a>, если они «влезают» целиком, а теги , если не влезают целиком, разделять построчно. Если же это однострочник на >4000 символов, то дробить уже посимвольно. С тегом <b> аналогичная логика, но дробим пословно.

static_lab ★★★★★
()
Ответ на: комментарий от static_lab

Почему? Можно в первое сообщение пустить 15 строк кода на 4000 символов, а во второе — оставшиеся 5 строк на 1000 символов

почему телега отбросит разрезанный тег <code>?

ну правила у нее такие. если в отправленном тексте есть <code> после которого нет </code> - получается ошибка, сообщение не отправляется. надо либо добавить недостающий закрывающий тег либо отправить как простой текст без форматирования

вот так просто нельзя разрезать к сожалению
<code>
print 1
print 2
------------cut--------------
print 3
print 4
</code>

theurs ★★
() автор топика
Ответ на: комментарий от static_lab

Так тебе нужно решение или ты просто жалуешься?

мне нужно решение, и лучше готовое. телеграм штука популярная, наверняка уже 100 раз до меня сделано

theurs ★★
() автор топика
Ответ на: комментарий от static_lab

Ты вообще читал, например, то, что тебе выше написал @E? Если тебе надо разделить тег, то ты его в первом чанке закрываешь, а во втором — открываешь снова.

sax парсер? для такого текста он подойдет? по-моему в xml всё должно быть внутри тегов

theurs ★★
() автор топика
Ответ на: комментарий от theurs

sax парсер? для такого текста он подойдет? по-моему в xml всё должно быть внутри тегов

То есть всё-таки моё сообщение ты не читал? Повторю ещё раз:

И вообще приведённый код больше похож на какой-нибудь Markdown в том смысле, что абзацами считается блок текста, отделённый пустой строкой. В случае настоящего HTML здесь были бы или . А текст как здесь браузер, интерпретируя как настоящий HTML, превратит в одну большую простыню текста одним абзацем.

Так что в данном случае стоит написать свой парсер […]

Я изначально пытался выяснить, в каком формате передаются данные. И это, судя по всему, более Markdown с HTML-тегами, нежели HTML (https://i.imgur.com/lv1JFzi.png). Поэтому SAX-парсер здесь не сработает.

И да, всё-таки нужно разобраться с форматированием многострочного <code>. Строки просто \n разделяются или \n\n, или ещё как-нибудь?

static_lab ★★★★★
()
Ответ на: комментарий от static_lab

Я изначально пытался выяснить, в каком формате передаются данные.

Изначально было написано что это хтмл форматирование для телеграма, теги <p> <br> итп он тоже не принимает, их надо экранировать что бы сообщение с ними пропустили

как маркдаун, да, строки разделены \n

с тегом <code> и <b> всё более менее понятно, после разделения можно посчитать открытые и закрытые и добавить недостающие

а вот как резать тег <a> учитывая что у него внутри может быть еще что то

<a href=«очень длинная ссылка» title=«с очень длинной всплывающей подсказкой»> и большой текст между открывающим и закрывающим тегом</a>

theurs ★★
() автор топика
Ответ на: комментарий от theurs

Пример с ссылками - простой текст большого размера, скажем 3800 символов и после него список ссылок, длинных, еще на пару тысяч символов

по хорошему разрез надо сделать где то в районе блока ссылок, после первой или второй

theurs ★★
() автор топика
Последнее исправление: theurs (всего исправлений: 1)
Ответ на: комментарий от theurs

а вот как резать тег учитывая что у него внутри может быть еще что то

Вот вычитываешь этот тег целиком и смотришь: влезает ли он у тебя в старый чанк или нужно создавать новый? А уж если весь этот тег в лимит символов не вмещается, то это уже вопрос к тебе, как к заказчику, что с ним делать: дробить текст внутри, отправлять href в сокращатель ссылок или ещё что-то.

static_lab ★★★★★
()
Ответ на: комментарий от static_lab

Вот вычитываешь этот тег целиком и смотришь: влезает ли он у тебя в старый чанк или нужно создавать новый? А уж если весь этот тег в лимит символов не вмещается, то это уже вопрос к тебе, как к заказчику, что с ним делать: дробить текст внутри, отправлять href в сокращатель ссылок или ещё что-то.

как и чем вычитывать этот тег? это же не настоящий хтмл текст

можно попробовать регэкспом заменить ссылки на рандомные слова такой же длины, потом нарезать обычной нарезалкой для текстов из стандартной бибилотеки, она старается делать разрез в конце абзаца или предложения или между слов смотря как получится

и потом заменить обратно

но это всё выглядит как линукс мобиль, а хочется нормальное решение

theurs ★★
() автор топика
Ответ на: комментарий от theurs

телеграм это не только телефончики но и десктопные клиенты с огромными экранами, они вполне могут читать большие тексты

без разницы. Телега взвизгнет по разу на каждый кусок. И будут N непрочитанных сообщений.

Считайте что за каждое сверх одного вас кроют матом, а за более 5 хотят стукнуть по голове ;-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

без разницы. Телега взвизгнет по разу на каждый кусок. И будут N непрочитанных сообщений

это зависит от того что бот делает. если спам шлет то и одной строчки хватит что бы заблокировать. а если ты сам запросил этот текст то какие проблемы?

theurs ★★
() автор топика
Ответ на: комментарий от theurs

Ссылка длиннее 4к символов? Мне припоминается что у URLов есть лимит длинны какой-то, но даже если нет то это дичь. А я думал что мои ссылки на 250 символов это жесть и срам

MrClon ★★★★★
()
Ответ на: комментарий от MrClon

Ссылка длиннее 4к символов?

если попадется такая ссылка то её в телеграм никак не протолкнешь, даже без форматирования Ж(


сделал так. вроде даже работает

# найти и заменить все ссылки (тэг <a>) на рандомные слова с такой же длиной
# разбить текст на части стараясь делать разрез по абзацу, строке или пробелу в таком порядке
# в каждом куске проверить совпадение количества открывающих и закрывающих
# тэгов <b> <code> и заменить рандомные слова обратно на ссылки

def split_html(text: str, max_length: int = 1500) -> list:
    """
    Split the given HTML text into chunks of maximum length, while preserving the integrity
    of HTML tags. The function takes two arguments:
    
    Parameters:
        - text (str): The HTML text to be split.
        - max_length (int): The maximum length of each chunk. Default is 1500.
        
    Returns:
        - list: A list of chunks, where each chunk is a part of the original text.
        
    Raises:
        - AssertionError: If the length of the text is less than or equal to 299.
    """

    assert len(text) > 299, 'Длина текста должна быть больше 299'

    #найти и заменить все ссылки (тэг <a>) на рандомные слова с такой же длиной
    links = []
    soup = BeautifulSoup(text, 'html.parser')
    a_tags = soup.find_all('a')
    for tag in a_tags:
        tag = str(tag)
        random_string = ''.join(random.choice(string.ascii_uppercase+string.ascii_lowercase) for _ in range(len(tag)))
        links.append((random_string, tag))
        text = text.replace(tag, random_string)

    # разбить текст на части
    chunks = telebot.util.smart_split(text, max_length)
    chunks2 = []
    next_chunk_is_b = False
    next_chunk_is_code = False
    # в каждом куске проверить совпадение количества открывающих и закрывающих
    # тэгов <b> <code> и заменить рандомные слова обратно на ссылки
    for chunk in chunks:
        for random_string, tag in links:
            chunk = chunk.replace(random_string, tag)

        b_tags = chunk.count('<b>')
        b_close_tags = chunk.count('</b>')
        code_tags = chunk.count('<code>')
        code_close_tags = chunk.count('</code>')

        if b_tags > b_close_tags:
            chunk += '</b>'
            next_chunk_is_b = True
        elif b_tags < b_close_tags:
            chunk = '<b>' + chunk
            next_chunk_is_b = False

        if code_tags > code_close_tags:
            chunk += '</code>'
            next_chunk_is_code = True
        elif code_tags < code_close_tags:
            chunk = '<code>' + chunk
            next_chunk_is_code = False

        # если нет открывающих и закрывающих тегов <code> а в предыдущем чанке 
        # был добавлен закрывающий тег значит этот чанк целиком - код
        if code_close_tags == 0 and code_tags == 0 and next_chunk_is_code:
            chunk = '<code>' + chunk
            chunk += '</code>'

        # если нет открывающих и закрывающих тегов <b> а в предыдущем чанке 
        # был добавлен закрывающий тег значит этот чанк целиком - <b>
        if b_close_tags == 0 and b_tags == 0 and next_chunk_is_b:
            chunk = '<b>' + chunk
            chunk += '</b>'

        chunks2.append(chunk)

    return chunks2

theurs ★★
() автор топика
Последнее исправление: theurs (всего исправлений: 1)
Ответ на: комментарий от theurs

Если разрез всё же попадет на длинную ссылку то она превратится в 2 длинных куска рандомных букв...форматирование в телеграме не сломается но ссылка покинет чат

theurs ★★
() автор топика
Ответ на: комментарий от vvn_black

Поправьте, если я ошибаюсь, но мне такая дурная мысль пришла в голову, что вы этот «контент» берёте для своего бота из других тг-ботов?

Контент генерируют чат боты, chatGPT и другие. Ну и некоторые другие модули могут текст создать, например OCR работает с помощью tesseract, может создать много текста из картинки.

theurs ★★
() автор топика
Ответ на: комментарий от vvn_black

Поправьте, если я ошибаюсь, но мне такая дурная мысль пришла в голову, что вы этот «контент» берёте для своего бота из других тг-ботов?

Если ты про то что в коде коменты то на русском то на английском то это просто работа копайлота, он пишет на английском. А я на русском Ж) Получается такой вот треш.

theurs ★★
() автор топика

В общем виде задача не решаема ибо

если длина тегов префикса достигают ~2к - то содержимому нет места на передачу - ибо предполагаем что разрез делаем внутри содержимого тега и культурно вставляем в место разреза все закрытия тегов что бы в следующем посте повторить отрыкытия тегов

если же при разрезании закрываем(а в следующем сообщении открываем) только текущий тег - то вообще не видно проблемы

qulinxao3
()