Несколько нумерованных списков с помощью python-docx

Мне нужно сгенерировать много похожего одностраничного контента в одном файле docx для личных целей, поэтому я создал скрипт Python для автоматизации этого. Часть этого контента представляет собой пронумерованный список, но, к сожалению, нумерация продолжается и от страницы к странице, например:


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut Labore et dolore magna aliqua. Ut enim реклама minim veniam, quis nostrum упражнения ullamco Laboris Nisi ut aliquip ex ea commodo consequat.

1. Элемент списка1

2. Элемент списка2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum долоре eu fugiat nulla pariatur. За исключением sint occaecat cupidatat non гордый, сун в culpa qui officia deserunt mollit anim id est трудум.

<--- Разрыв страницы -->

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut Labore et dolore magna aliqua. Ut enim реклама minim veniam, quis nostrum упражнения ullamco Laboris Nisi ut aliquip ex ea commodo consequat.

3. Элемент списка1

4. Элемент списка2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum долоре eu fugiat nulla pariatur. За исключением sint occaecat cupidatat non гордый, сун в culpa qui officia deserunt mollit anim id est трудум.


И я хочу, чтобы это выглядело так:


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut Labore et dolore magna aliqua. Ut enim реклама minim veniam, quis nostrum упражнения ullamco Laboris Nisi ut aliquip ex ea commodo consequat.

1. Элемент списка1

2. Элемент списка2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum долоре eu fugiat nulla pariatur. За исключением sint occaecat cupidatat non гордый, сун в culpa qui officia deserunt mollit anim id est трудум.

<--- Разрыв страницы -->

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut Labore et dolore magna aliqua. Ut enim реклама minim veniam, quis nostrum упражнения ullamco Laboris Nisi ut aliquip ex ea commodo consequat.

1. Элемент списка1

2. Элемент списка2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum долоре eu fugiat nulla pariatur. За исключением sint occaecat cupidatat non гордый, сун в culpa qui officia deserunt mollit anim id est трудум.


Чтобы предоставить более подробную информацию о том, как работает мой код, предположим, что у меня есть список страниц, из которого можно получить список элементов на основе страницы, и это реализовано в функции get_items(page). Учитывая вышесказанное, мой код в настоящее время выглядит примерно так (для простоты я исключаю абзацы форматирования):

document = Document()
pages = [...]                      # list of pages
for page in pages:
    document.add_paragraph("...")  # put some regular text to the page
    items = get_items(page)
    for item in items:
        p = document.add_paragraph(item, style='List Number 2')     # 'Line Numer 2' is for some extra indent
    document.add_paragraph("...")  # put some regular text to the page
    document.add_page_break()      # add page breaks to start from a new page
document.save("...")               # save the document

Взгляните на этот комментарий: stackoverflow.com/a/78685353

DaSt 09.08.2024 22:33

@ДаСт, спасибо!

Glenn 09.08.2024 22:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Когда я просмотрел комментарий SO, упомянутый DaSt, стало ясно, что нет прямого способа добавить более трех нумерованных списков в один документ с отдельной нумерацией. Решение абстрактной нумерации кажется слишком сложным, поэтому самый простой способ решения этой проблемы, который я вижу, заключается в следующем:

LEFT_INDENT = Pt(36)               # sample left indent for numbered list
document = Document()
pages = [...]                      # list of pages
for page in pages:
    document.add_paragraph("...")  # put some regular text to the page
    items = get_items(page)
    for i in range(len(items)):
        p = document.add_paragraph(f"{i + 1}. {items[i]}")
        p.paragraph_format.left_indent = LEFT_INDENT
    document.add_paragraph("...")  # put some regular text to the page
    document.add_page_break()      # add page breaks to start from a new page
document.save("...")               # save the document

Мой ответ в нумерации списка перезапуска python-docx заключается в том, чтобы объяснить проблему и предложить два решения.

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

Пример:

from docx import Document
from docx.text.paragraph import Paragraph

def prepare_numberings(document: Document, style_name: str) -> int:
    #prepare the numberings to have a new numbering, which points to the same abstract numbering, 
    #the style style_name also points to but has start override set
    styles = document.styles
    #get numId to which style style_name links
    num_id_list_number = -1
    for style in styles:
        if (style.name == style_name):
            num_id_list_number = style._element.pPr.numPr.numId.val
    #add new numbering linking to same abstractNumId but has startOverride 
    #and get new numId
    num_id_list_number_new = -1
    if (num_id_list_number > -1):        
        ct_numbering = document.part.numbering_part.numbering_definitions._numbering
        ct_num = ct_numbering.num_having_numId(num_id_list_number)
        abstractNumId = ct_num.abstractNumId.val
        ct_num = ct_numbering.add_num(abstractNumId)
        num_id_list_number_new = ct_num.numId
        startOverride = ct_num.add_lvlOverride(0)._add_startOverride()
        startOverride.val = 1
    return num_id_list_number_new;
    
def set_link_to_numId(paragraph: Paragraph, num_id: int):
    if num_id > -1:
        numPr = paragraph._element.pPr._add_numPr()
        numPr._add_numId().val = num_id
    

# Main program logic

document = Document()

text_1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'
text_2 = 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
pages = [['List 1 Item 1','List 1 Item 2'], ['List 2 Item 1','List 2 Item 2','List 2 Item 3','List 2 Item 4'], ['List 3 Item 1','List 3 Item 2','List 3 Item 3']] # list of list items in pages

for page in pages:
    document.add_paragraph(text_1) # put some regular text to the page
    #items = get_items(page)
    items = page

    #prepare the numberings to have a new numbering, which points to the same abstract numbering, 
    #the style 'List Number 2' also points to but has start override set 
    num_id_list_number_new = prepare_numberings(document, 'List Number 2')
    item_count = 0
    for item in items:
        p = document.add_paragraph(item, style='List Number 2') # 'Line Numer 2' is for some extra indent
        if item_count == 0:
            #first paragraph in new list links to new numId having startOverride
            set_link_to_numId(p, num_id_list_number_new)
        item_count += 1
         
    document.add_paragraph(text_2) # put some regular text to the page
    document.add_page_break() # add page breaks to start from a new page

document.save('test.docx')

Все еще слишком сложно?

Нет необходимости быть пассивно-агрессивным с вопросом «Все еще слишком сложно?»; Я никогда не говорил, что ваше решение плохое или что-то в этом роде 🤷‍♀️. Просто нет необходимости делать весь этот код для личных целей, все равно есть счетчик нумерации элементов, поэтому мне проще сделать так, как я сделал. Если бы проект был производственным, то, возможно, ваше решение было бы лучше, это более правильный путь и, вероятно, имело свои преимущества. Суть вопроса заключалась в том, чтобы спросить, есть ли какой-нибудь прямой путь без ссылки на классы низкого уровня. Вот и все.

Glenn 10.08.2024 13:48

Другие вопросы по теме