Script para Índice remissivo no Scribus

Previous topic - Next topic

lucasnwd

PT-BR

Trabalho diagramando livros de filosofia e meu trabalho me exige criar um indice com as palavras mais frequentes do livro, indicando em quais páginas ela aparecem (um índice remissivo). Desta forma, eu fiz um script simples de Python para encontrar essas palavras de forma um pouco mais automática.

Eu ainda não sei como fazer o script, aceitar várias entradas de uma vez (eu não sei quase nada de Python), mas ele já ajuda bastante.

Para usar:
1 - selecione a caixa de texto na qual quer pesquisar as palavras.
2- abra o console e cole o seguinte código, substituindo "psicologia" pela palavra de sua escolha:
import scribus

word = "psicologia"
occurrence_pages = []

for page_num in range(scribus.pageCount()):
    scribus.gotoPage(page_num + 1)
    for item in scribus.getAllObjects():
        if scribus.getObjectType(item) == "TextFrame":
            if scribus.getTextLength(item) > 0:
                text = scribus.getText(item)
                if word in text:
                    occurrence_pages.append(page_num + 1)
                    break

print(f"{word}: {', '.join(map(str, occurrence_pages))}")
3 - Pressione F9 para executar o código e ele retornará a palavra e em quais paginas ela aparece.

Quem souber mais sobre Python e quiser criar uma interface, ou aprimorar o código para recerber diversas entradas ao mesmo tempo e já escrevê-las em uma caixa de texto na última página do arquivo, por exemplo, ajudaria muito a facilitar o trabalho dos diversos diagramadores e acadêmicos que usam o Scribus.


EN (TRANSLATED WITH GOOGLE)

I work designing philosophy books and my job requires me to create an index with the most frequent words in the book, indicating which pages they appear on (an index). So, I made a simple Python script to find these words a little more automatically.

I still don't know how to make the script accept multiple inputs at once (I know almost nothing about Python), but it already helps a lot.

To use:
1 - select the text box in which you want to search for the words.
2- open the console and paste the following code, replacing "psychology" with the word of your choice:
import scribus

word="psychology"
occurrence_pages = []

for page_num in range(scribus.pageCount()):
     scribus.gotoPage(page_num + 1)
     for item in scribus.getAllObjects():
         if scribus.getObjectType(item) == "TextFrame":
             if scribus.getTextLength(item) > 0:
                 text = scribus.getText(item)
                 if word in text:
                     occurrence_pages.append(page_num + 1)
                     break

print(f"{word}: {', '.join(map(str, occurrence_pages))}")
3 - Press F9 to run the code and it will return the word and which pages it appears on.

Anyone who knows more about Python and wants to create an interface, or improve the code to receive several inputs at the same time and already write them in a text box on the last page of the file, for example, would help a lot to facilitate the work of the various diagrammers and academics who use Scribus.

a.l.e

hi lucas

i'm the author of https://github.com/aoloe/scribus-script-repository/tree/master/table-of-contents , a python script for creating a table of content based on the document styles.

i would be interested in working on a script for creating an index.

would it possible for you to share with me a .sla (i only need the .sla not the images or the fonts) that i can use as the sample?
i think that it would help, to have a real life example and being able to iterate with you to improve the result.

farzan

Quote from: a.l.e on June 07, 2023, 08:37:44 AMhi lucas

i'm the author of https://github.com/aoloe/scribus-script-repository/tree/master/table-of-contents , a python script for creating a table of content based on the document styles.

i would be interested in working on a script for creating an index.

would it possible for you to share with me a .sla (i only need the .sla not the images or the fonts) that i can use as the sample?
i think that it would help, to have a real life example and being able to iterate with you to improve the result.

That would be great. Would it be feasible to consider support for right-to-left (Arabic/Persian) languages from the beginning?

a.l.e

hi farzan,

if you provide documents for testing and participate in the testing, then this is more likely to happen.

sadly lucas did not provide any document or further input on how an index for scribus could work.

today, i will try to do some work on this topic and, currently, i'm basing my prototype on a few resources like:

- https://wiki.scribus.net/canvas/Notes_toward_having_an_index
- https://latex-tutorial.com/creating-index-latex/

but i think that i have never created an index in my life and i normally do not use them either when reading books (if the book is well structured, the table of contents is mostly enough; and if the book is not well structured, the index does not help much either...) so i'm really not an expert on the topic : - (

a.l.e

RTL cannot correctly be supported until the scripter API provides access to the sections information.

https://bugs.scribus.net/view.php?id=15683

a.l.e

On Thursday evening, I was at the local Hackergarten and I've suggested that we could work on this project.

Laura, Severin, and Rohit joined me: we brainstormen how an index could work and managed to produce some "basic" code.

This is the (somehow messy) proof of concept we have produced:

from collections import defaultdict
# import string
import re

index_config_file = {"Lorem": {"alias": ["lorem"]}, "primis": 2, "odio": 0, "dolor": 0}
words_for_index = set()
for word in index_config_file.keys():
    # remove poncutation (and -) from the words
    # words_for_index.add(word.lower().translate(str.maketrans('', '', string.punctuation)))
    words_for_index.add(word.lower())
    # words_for_index = {"lorem", "primis", "odio", "dolor"}

def main():
    index = Index()
    # index.read_config()
    for page in range(2):
        index.process_frame(text[page], 0)
    index.print()

# TODO: unit testing:
# Schiff Schiffbruch
# Cloud-basierte Lösung
class Index:
    def __init__(self):
        self.index = defaultdict(set)

    def process_frame(self, frame_text, page_number):
        frame_text = frame_text.lower()
        for word in words_for_index:
            # TODO: create a list of patterns?
            pattern = r'\b'+word+r'\b'
            # if word in frame_text:
            if re.search(pattern, frame_text):
                self.index[word].add(page_number)

           

    def process_frame2(self, frame_text, page_number):
        # TODO: translate also removes the dashes: we need to remove the dash from the words provided by the user
        frame_text = frame_text.translate(str.maketrans('', '', string.punctuation))
        # words = ''.join(e for e in frame_text.lower if e.isalnum() or e.isspace() or e in ['-']).split(' ')
        words = frame_text.lower().split(' ')
        for word in words:
            if word in words_for_index:
                self.index[word].add(page_number)

    def print(self):
        print(self.index)
   
   


text = ["Lorem-ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. Nulla placerat porta justo. Nulla vitae turpis. Praesent lacus.",
"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam ultricies lacus eu dui. Duis viverra risus et eros. Aenean odio dolor, tristique quis, commodo id, posuere sit amet, dui. Pellentesque velit. Aliquam erat volutpat. Duis sagittis nibh sed justo. Sed ultrices nisl sed pede. Sed tempor lorem in leo. Integer gravida tincidunt nunc. Vivamus ut quam vel ligula tristique condimentum. Proin facilisis. Aliquam sagittis lacinia mi. Donec sagittis luctus dui. Maecenas quam ante, vestibulum auctor, blandit in, iaculis in, velit. Aliquam at ligula. Nam a tellus. Aliquam eu nulla at turpis vulputate hendrerit. Proin at diam. Curabitur euismod.",
]


if __name__ == "__main__":
    main()

The code above searches for a list of words in a text that is on different pages (in this proof of concept the text comes from a list of "Lorem Ipsum", not yet from a Scribus document).

It's far from being finished, but a first step in the good direction.

While writing this code, step by step, we discussed several use cases and identified multiple edge cases that have to be taken into account.

As a reference for our work, we have used the index in Cedric Gemy's Scribus, Premières mises en pages professionnelles.

a.l.e

Here a request to the community: how should the user define which words will be in the index?

We have have a few ideas, but we could not (yet) find a good way of doing.

Can anybody who has some experience in creating indexes raise the end and tell us how they wish to do it?
(Personally, I've only created one single index in the past and that was many many years ago (and it was in Latex... with a very different way of defining things as in Scribus))

Nermander

I think the "best practice" is to use a separate style for indexed words.

If there is to be something more automatic I guess there needs to be some kind of "exceptions list" to exclude words that should not be in the index, but this will then probably need to be at least language specific, of not even document specific. And I guess it may need to be in a separate file, while the style solution does not need anything external.

The main issue I guess is that using a style means the index words will need to have the same appearance, and that I guess complicates things a bit.