[SOLVED] Jedno słowo na jeden wiersz + chmura słów

Makropolecenia i funkcje w języku Basic
Awatar użytkownika
quest-88
Posty: 1105
Rejestracja: ndz maja 24, 2009 8:12 pm
Lokalizacja: Zabrze
Kontakt:

[SOLVED] Jedno słowo na jeden wiersz + chmura słów

Post autor: quest-88 »

Witam

Nie jest to jeszcze realny problem, a przygotowanie do zadania.

Muszę scharakteryzować słownictwo użyte z miesięczniku (6 edycji), który ma ~ 150 stron. Pomyślałem, że najlepiej byłoby zeskanować programem OCR co dziesiątą stronę każdego numeru. W ten sposób stworzyłbym bazę wyrażeń. Raczej nie ma co liczyć na integrację z OO.o, ale też nie powinno być problemu z importem de facto czystego tekstu zapisanego w Wordzie czy Excelu.

Z sześciu wydań będzie to 90 stron tekstu z porozrzucanymi i pomieszanymi słowami w całych zdaniach. Problem polega na tym, że - dla zwiększenia czytelności - należałoby porozdzielać te słowa, tak by na jeden wiersz/komórkę (Writer/Calc - preferuję ten drugi) przypadało jedno słowo.

I banalny przykładzik. :) Zdanie "Ala ma kota, a kot ma pchły". Zdanie to powinno zostać podzielone na części:
-Ala
-ma
-kota
-a
-kot
-ma
-pchły

Następnie taki zbiór będę musiał alfabetycznie posortować, ale to już jest czynnością banalną.

Proszę o pomoc. :)
Standardowa diagnostyka rozwiązuje 90% problemów typu "wcześniej działało, ale już nie działa".
Przepis na LibreOffice
Uzyskałeś pomoc? Poinformuj innych o sprawdzonym rozwiązaniu i podziękuj. Dodaj [SOLVED] w tytule.
Jan_J
Posty: 4557
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: Jedno słowo na jeden wiersz/jedną komórkę

Post autor: Jan_J »

Filtrem go, filtrem.
1. wszystkie znaki przestankowe na spacje
2. wszystkie grupy spacji na entery
3. ujednolicić pisownię wielkimi/małymi literami (tylko małe?)
4. sort
Razem, przy użyciu filtrów uniksowych, zrobisz to mniej więcej tak:

Kod: Zaznacz cały

cat tekst.txt | tr "[\.,;:]"  " "  | sed -e "s/  */\n/g" | tr "A-ZĄĆĘŁŃÓŚŹŻ" "a-ząćęłńóśźż" | sort -i > wynik.txt
Pisane z palca bez dogłębnego sprawdzania, więc mogą być nieścisłości.
Wynik możesz sobie wczytać do calca.
Jest to potężne narzędzie dla kogoś, kto się nie boi konsoli i formatu tekstowego. W tym przypadku zalecanie rozwiązań wewnątrz pakietu biurowego jest tylko półśrodkiem -- do podobnych prac nic lepszego od filtrów nie wymyślono od 30 lat.

Punkty 1. i 2. da się połączyć zastępując grupy znaków przestankowych i/lub spacji pojedynczym enterem.

Btw: konstrukcja
sort -i | uniq -c | sort -n
zlicza Ci powtórzenia z krotnościami i sortuje wg częstości. Ale wcześniej zapewne trzeba sobie poradzić z fleksją.
JJ
LO (7.6) ∙ AOO (4.1) ∙ Python (3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
Awatar użytkownika
quest-88
Posty: 1105
Rejestracja: ndz maja 24, 2009 8:12 pm
Lokalizacja: Zabrze
Kontakt:

Re: Jedno słowo na jeden wiersz/jedną komórkę

Post autor: quest-88 »

Dziękuję za skuteczny filtr.

Zeskanowałem około 160 stron treści, którą zapisałem jako czysty tekst (plik tekst.txt). Plik ten potraktowałem polecanym filtrem, po czym pousuwałem spacje, kwadraty, znaki potęg i inne dziwne symbole (było tego prawie 5 tysięcy wierszy). Potem musiałem sprowadzić wyrazy do ich podstawowej formy. Skorzystałem tutaj z programu Morfologik-stemming 1.4.0. Akurat program jest nieskomplikowany i wszystko podpowiada. Wystarczyło wklepać komendę i wynik był po paru sekundach.

Kod: Zaznacz cały

quest2@quest:~/Downloads/morfologik-stemming-1.4.0$ java -jar morfologik-stemming-1.4.0.jar plstem -i wynik.txt -ie UTF-8 -o wynik2.txt
Input encoding: UTF-8
Output encoding: UTF-8
Processed 57,771 words in 0.785 seconds (73594 words per second).
Zawartość pliku wynik2.txt prezentuje się bardzo ładnie.
abolicją abolicja subst:sg:inst:f
abolicji abolicja subst:pl:gen:f+subst:sg:gen.dat.loc:f
abonament abonament subst:sg:nom.acc:m3
abonament abonament subst:sg:nom.acc:m3
abonamentu abonament subst:sg:gen:m3
abonenci abonent subst:pl:nom.voc:m1
Jak widać w zacytowanym tekście, forma podstawowa mieści się w drugiej kolumnie (mamy odmienione słowo, jego podstawową formę i informacje o wyrazie - czy to rzeczownik/czasownik/..., czy jest w liczbie mnogiej czy pojedynczej itd.)

Teraz pozostało wyodrębnić tylko formę podstawową:

Kod: Zaznacz cały

awk -F'\t' '{print $2}' wynik2.txt > wynik3.txt
I zliczyć powtórzenia i częstość występowania:

Kod: Zaznacz cały

cat wynik3.txt | tr "[\.,;:]"  " "  | sed -e "s/  */\n/g" | tr "A-ZĄĆĘŁŃÓŚŹŻ" "a-ząćęłńóśźż" | sort -i | uniq -c | sort -n > wynik4.txt
Teraz kombinuję jak zrobić z tego "chmurę tagów".
Standardowa diagnostyka rozwiązuje 90% problemów typu "wcześniej działało, ale już nie działa".
Przepis na LibreOffice
Uzyskałeś pomoc? Poinformuj innych o sprawdzonym rozwiązaniu i podziękuj. Dodaj [SOLVED] w tytule.
Jan_J
Posty: 4557
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: Jedno słowo na jeden wiersz/jedną komórkę

Post autor: Jan_J »

Cześć,
ja bym zaproponował:

założyć ile rozróżnialnych kategorii stylów ma być w chmurze, i jakie mają być ich wartości progowe (zapewne w skali logarytmicznej?)
zastępować pary (krotność, słowo) odwołaniami (piszę w postaci xhtml, ale możesz chcieć xlinka albo co) typu <a class="klasa dla tej krotności" href="cokolwiek chcesz">słowo<a>
najważniejsze to
* umieć wyznaczyć nazwę klasy dla znanego numeru. sed jest do tego za cieńki, chyba że operujesz logarytmem dziesiętnym, wtedy długość numeru wyznacza klasę i od biedy sobie poradzisz. Ale w awk masz liczby, trzeba se tylko funkcję napisać
* mieć do czego odsyłać.
JJ
LO (7.6) ∙ AOO (4.1) ∙ Python (3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
Awatar użytkownika
quest-88
Posty: 1105
Rejestracja: ndz maja 24, 2009 8:12 pm
Lokalizacja: Zabrze
Kontakt:

Re: [SOLVED] Jedno słowo na jeden wiersz/jedną komórkę

Post autor: quest-88 »

Problem ten rozwiązałem w inny sposób. Plikowi wynik4.txt zmieniłem rozszerzenie na wynik4.csv i zaimportowałem do Calca. Przed zatwierdzeniem importu tekstu, należy zaznaczyć pole wyboru Scal separatory (Merge delimiters) w części Opcje separatora (Separator options). Potem można kliknąć w przycisk OK.

Jeśli po imporcie danych, pierwsza kolumna będzie pusta, po prostu ją usuwamy. Robimy tak, by w kolumnie "A" widniała ilość powtórzeń danego słowa, a w kolumnie "B" dane słowo (patrz: zdjęcie kolumny.png).

Samą chmurę wygenerowałem makrem, ale o tym za chwilę.

Posiadam procesor Pentium 4 3,2 Ghz. Próba "wychmurzenia" 11 tysięcy słów skończyła się zamrożeniem całego systemu i resetem komputera. Podobno na dwurdzeniowym procesorze 1,6 Ghz działa bez problemów. :)

Aby sobie z tym poradzić, musiałem nadać OO.o wyższy priorytet.

Kod: Zaznacz cały

quest2@quest:~$ ps ax
 2287 ?        Sl     0:04 /opt/ooo-dev3/program/soffice.bin

Kod: Zaznacz cały

quest2@quest:~$ renice +18 2287
2287: old priority 0, new priority 18
I teraz przechodzimy do głównej części. Dodajemy makro, które następnie wykonujemy.

Kod: Zaznacz cały

REM  *****  BASIC  *****

' Copyright (c) 2010, Paweł Smoliński
' All rights reserved.

' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'  * Redistributions of source code must retain the above copyright
'    notice, this list of conditions and the following disclaimer.
'  * Redistributions in binary form must reproduce the above copyright
'    notice, this list of conditions and the following disclaimer in the
'    documentation and/or other materials provided with the distribution.
'  * Neither the name of the Paweł Smoliński nor the names of its
'    contributors may be used to endorse or promote products derived from
'    this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
' TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
' PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
' EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
' PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
' OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
' WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
' OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
' ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

' Utworzenie "chmury tagów" na podstawie danych pobranych z arkusza kalkulacyjnego:
' - z kolumny A ilości wystąpień danego wyrazu
' - z kolumny B same wyrazny
' - dane pobierane są z 1 arkusza, jeżeli mają być pobierane z innego należy odpowiednio zmodyfikować kod
' UWAGA! Z uwagi na to, iż kod ten pisany był pod konkretne rozwiązanie, posiada on tylko prosty mechanizm
'        walidacji i oczekuje, iż użytkownik wprowadzi poprawne zakresy danych
Sub Main

Dim InputDoc as Object 'Dokument Calc'a
Dim Sheet as Object 'Pojedynczy arkusz
Dim Cell as Object 'Pojedyncza komórka w arkuszu
Dim ResultDoc as Object 'Wynikowy dokument tekstowy (Writer)
Dim TxtCursor as Object 'Kursor w dokumencie tekstowym
Dim Dummy() 'Pusta funkcja
Dim MinCol as Integer 'Minimalny indeks kolumny brany pod uwagę(dla A1=1, A3=3 itp.)
Dim MaxCol as Integer 'Maksymalny indeks kolumny brany pod uwagę
Dim I as Integer 'Zmienna pomocnicza
Dim C as Integer '      -"-
Dim W as String  '      -"-
Dim MinHeight as Integer 'Minimalna wielkość czcionki, jaka zostanie użyta
Dim MaxHeight as Integer 'Maksymalna wielkość czcionki, jaka zostanie użyta
Dim HeightDiff as Integer 'Różnica w wielkości czcionki
Dim CurrHeight as Single 'Zmienna pomocnicza - wysokość bieżącego wyrazu
Dim MinCount as Integer 'Minimalna liczba wystąpień w podanym zestawie
Dim MaxCount as Integer 'Maksymalna liczba wystąpień w podanym zestawie
Dim CountDiff as Integer 'Różnica w liczbie wystąpień
Dim Cells as Object 'Zmienna pomocnicza - zbiór komórek opisujących liczbę wystąpień
Dim SpaceHeight as Integer 'Wysokość czcionki używanej przy wstawianiu spacji
Dim AddNumbers as Integer 'Informacja czy pokazywać obok wyrazów ilości wystąpień

SpaceHeight = 12 ' <=- Jeżeli czcionka dla spacji ma mieć inną wysokość, zmień tą wartość

' Wprowadzamy zakres wierszy, jakie będą brane pod uwagę
MinCol = InputBox("Wprowadź indeks pierwszego wiersza")
MaxCol = InputBox("Wprowadź indeks ostatniego wiersza")

' Prosta walidacja
If (MinCol < 1 or MaxCol < 1 or MinCol >= MaxCol) Then
	MsgBox("Podano nieprawidłowe indeksy wierszy")
	Exit Sub
End If

' Wprowadzamy graniczne wielkości czcionek
MinHeight = InputBox("Wprowadź minimalny rozmiar czcionki")
MaxHeight = InputBox("Wprowadź maksymalny rozmiar czcionki")

' Prosta walidacja
If (MinHeight < 1 or MaxHeight < 1 or MinHeight >= MaxHeight) Then
	MsgBox("Podano nieprawidłowe wielkości czcionek")
	Exit Sub
End If

' Pytanie o to czy pokazywać ilości wystąpień
AddNumbers = MsgBox("Pokazywać ilości wystąpień obok wyrazów?", MB_YESNO + MB_ICONQUESTION)

' Obliczamy Roznice wielkości czcionek
HeightDiff = MaxHeight - MinHeight

' Pobieramy instancję obiektu dokumentu oraz arkuszu
InputDoc = ThisComponent
Sheet = InputDoc.Sheets(0) ' <=- Tutaj dokonaj zmiany, jeżeli chesz operować na innym niż pierwszy arkusz

' Obliczamy maksymalną oraz minimalną liczbę wystąpień
Cells = Sheet.getCellRangeByName("A" + MinCol + ":A" + MaxCol)
MinCount = Cells.computeFunction(com.sun.star.sheet.GeneralFunction.MIN)
MaxCount = Cells.computeFunction(com.sun.star.sheet.GeneralFunction.MAX)
CountDiff = MaxCount - MinCount
If (CountDiff = 0) Then
	CountDiff = 1
End If

'Tworzymy instancję nowego dokumentu tekstowego oraz kursora w tym dokumencie
ResultDoc = StarDesktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, Dummy())
TxtCursor = ResultDoc.Text.createTextCursor()

'Lecimy pokolei po wszystkich kolumnach
For I = MinCol To MaxCol
	' Liczba wystąpień (C) oraz danych wyraz (W)
	C = Sheet.getCellRangeByName("A" + I).Value

	W = Sheet.getCellRangeByName("B" + I).String
	If(AddNumbers = IDYES) Then
		W = W + "(" + C + ")"
	End If
	' Obliczamy wysokość czcionki dla danego wyrazu i wstawiamy go do dokumentu
	CurrHeight = MinHeight + HeightDiff * (C - MinCount)/CountDiff
	TxtCursor.charHeight = CurrHeight
	TxtCursor.String = W
	TxtCursor.gotoEndOfParagraph(True)
	' Wstawiamy spację
	TxtCursor.charHeight = SpaceHeight
	txtCursor.String = " "
	TxtCursor.gotoEndOfParagraph(True)
Next I

End Sub
Wyskoczy okno z zapytaniem:
* Wprowadź indeks pierwszego wiersza - wpisujemy numer wiersza, od którego zaczynają się nasze dane, czyli wpisujemy 1.
* Wprowadź indeks ostatniego wiersza - analogicznie. Ja wpisałem 11279, bo tyle miałem.
* Minimalny rozmiar czcionki - 8 punktów.
* Maksymalny rozmiar czcionki - 30 punktów.
* Pokazywać ilości wystąpień obok wyrazów? - TAK/NIE.

Otworzy się Writer, w którym będzie się generować chmura słów (patrz: zdjęcie chmura słów.png). :)
Załączniki
kolumny.png
kolumny.png
chmura słów.png
chmura słów.png
Standardowa diagnostyka rozwiązuje 90% problemów typu "wcześniej działało, ale już nie działa".
Przepis na LibreOffice
Uzyskałeś pomoc? Poinformuj innych o sprawdzonym rozwiązaniu i podziękuj. Dodaj [SOLVED] w tytule.
Jan_J
Posty: 4557
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: [SOLVED] Jedno słowo na jeden wiersz + chmura słów

Post autor: Jan_J »

Grunt, żeby było skutecznie, i żeby się nie zapracować.
Czytam sobie wyniki: i jak tu zgadnąć, co to było za czasopismo?
JJ
LO (7.6) ∙ AOO (4.1) ∙ Python (3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
Awatar użytkownika
quest-88
Posty: 1105
Rejestracja: ndz maja 24, 2009 8:12 pm
Lokalizacja: Zabrze
Kontakt:

Re: [SOLVED] Jedno słowo na jeden wiersz + chmura słów

Post autor: quest-88 »

Pismo dla pań, "Caludia" wydawnictwa G+J. Z pojedynczych słówek naprawdę trudno coś wywnioskować jeśli nie jest się w temacie. W przyszłości trzeba będzie pomyśleć nad zdaniami, ale to już robota dla skanera OCR I Morfologika.
Standardowa diagnostyka rozwiązuje 90% problemów typu "wcześniej działało, ale już nie działa".
Przepis na LibreOffice
Uzyskałeś pomoc? Poinformuj innych o sprawdzonym rozwiązaniu i podziękuj. Dodaj [SOLVED] w tytule.
Jan_J
Posty: 4557
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: [SOLVED] Jedno słowo na jeden wiersz + chmura słów

Post autor: Jan_J »

Że dla pań, zgadnąć nietrudno. Ot, pomyślałem nieco wczorajszo: Kobieta i Życie.
JJ
LO (7.6) ∙ AOO (4.1) ∙ Python (3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
ODPOWIEDZ