Funkcja inteligentnie dzieląca kolumnę

Użytkowanie arkusza kalkulacyjnego
damienm
Posty: 2
Rejestracja: pt sie 12, 2011 1:25 am

Funkcja inteligentnie dzieląca kolumnę

Post autor: damienm »

Witam,

Mam ok 15 tyś wierszy w mniej więcej takim formacie:

"Dł­ugość: 300 mm@szerokość: 20 mm@wysokość: 15 mm"

Muszę wyfiltrować z tego do oddzielnych kolumn poszczególne parametry. Czyli np. w kolumnie A wyłącznie: "Długość: 300 mm" w kolumnie B "szerokość: 20 mm" itd. Filtrowany tekst jednak nie jest tak jednolity jak powyższy przykład. Może wyglądać np. tak:


"długo­ść: 3000 mm@szerokość: 2 mm@wysokość: 15 mm"

"wys­okość: 15 mm@długość: 3000 mm@szerokość: 2 mm"

"moc­: 15 kW@długość: 455 mm@szerokość: 2 mm@pojemność dzieży: 20 l"

Mógłbym zastosować "Tekst jako kolumny" gdyby nie fakt iż w każdej kolumnie może znajdować się tylko jeden konkretny parametr np. w kolumnie A wyłącznie długość a w B wyłącznie szerokość


Czy mogą Państwo mi jakoś pomóc w tym temacie? Jeśli to możliwe bardzo proszę o podanie formuły dla powyższych przykładów.

Pozdra­wiam

DM
OpenOffice 3.3 na Windows 7
Marek_Sz
Posty: 74
Rejestracja: pn lis 02, 2009 2:04 pm

Re: Funkcja inteligentnie dzieląca kolumnę

Post autor: Marek_Sz »

Nie wiem czy jest taka funkcja, ale ja proponowałbym następujące obejście problemu (przynajmniej na szybko nie przychodzi mi do głowy nic innego):

1) rozdzielić tekst na poszczególne kolumny funkcją "Tekst jako kolumny" łamiąc go na znaku"@"

2) w tym samym arkuszu albo osobnym wstawić formuły w pierwszej kolumnie wstawić formułę jeżeli wyświetlającą wartość komórki z informacją o długości, w drugiej kolumnie z informacją o szerokości itd. (tu przyda się zagnieżdżanie formuł w formułach w tym przypadku formuły jeżeli w formule jeżeli - popróbuj najpierw na jakichś prostych danych a potem skopiuj gotową formułę do docelowego arkusza; ilość znaków do sprawdzenia możesz ograniczyć zagnieżdżając formułę LEWY --> jeżeli(lewy(a1;3)="dłu";a1;jeżeli(...)))

3) po uporządkowaniu listy zaznacz całość i wklej specjalnie do nowego arkusza wklejając WARTOŚCI a nie formuły

Tyle na szybko, może zadziała; nie miałem czasu sprawdzić.
LibreOffice 5.0 na Windows 7 [praca] i LibreOffice 5.1 (64 bit) na Windows 7 [dom]
damienm
Posty: 2
Rejestracja: pt sie 12, 2011 1:25 am

Re: Funkcja inteligentnie dzieląca kolumnę

Post autor: damienm »

Witam,

Dziękuję. Jest to jakieś wyjście. Jednak spróbowałem wstępnie na 5 wierszach - zajęło to 6 min. Dużo ręcznej dłubaniny, i wiele możliwości pomyłki, konieczność maksymalnego skupienia. Prawdę mówiąc te 5 wierszy znacznie szybciej rozdzieliłbym ręcznie. Ogólnie ma to sens jedynie przy ciągu co najmniej kilkuset wierszy o identycznych parametrach w tekście. Jeśli jednak mam:

"długo­ść: 3000 mm@szerokość: 2 mm@wysokość: 15 mm"
"wys­okość: 15 mm@długość: 3000 mm@szerokość: 2 mm"
"moc­: 15 kW@długość: 455 mm@szerokość: 2 mm@pojemność dzieży: 20 l"
"długość: 13 mm@zasilanie: gaz@moc: 12 kW@wysokość: 345 mm"

a pod spodem jeszcze 15 tyś podobnych i niestety bardzo mało czasu.

Bardzo proszę o pomoc. Pozdrawiam
OpenOffice 3.3 na Windows 7
Jan_J
Posty: 4576
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: Funkcja inteligentnie dzieląca kolumnę

Post autor: Jan_J »

Jest to zadanie z przetwarzania tekstów. Do jego rozwiązania moim zdaniem najlepiej się nadają języki programowana zorientowane właśnie na przetwarzanie tekstu, takie jak awk, perl, python. Basica nie polecam, bo ma słabo rozwinięte struktury danych.

W arkuszu, nawet gdybyśmy mieli do dyspozycji sortowanie w poziomie, i tak pozostałby problem wyrównania nazw pól, które muszą "przejść" na nazwy kolumn.

Poniżej szkic rozwiązania w Pythonie. Zakładam, że 15 tysięcy wierszy mamy w pliku tekstowym (dane_in.txt). Wynik umieścimy w pliku dane_out.txt.

Kod: Zaznacz cały

# coding: utf-8

nazwapliku = 'dane_in.txt'
separator = '@'
kategorie = set([])
items = []
with open(nazwapliku) as plik:
        for item in plik.readlines():
                if item[0] == item[-2] == '"':
                        item = item[1:-2]
                item = item.split(separator)
                item = [x.split(':') for x in item]
                item = dict(item)
                kategorie.update(item.keys())
                items.append(item)

nazwapliku = 'dane_out.txt'
separator = '\t'
kategorie = tuple(kategorie)
with open(nazwapliku, 'w') as plik:
        plik.write(separator.join(kategorie) + '\n')
        for item in items:
                output = []
                for kat in kategorie:
                        try:
                                output.append(item[kat].strip())
                        except:
                                output.append('')
                plik.write(separator.join(output) + '\n')

Jeżeli nie masz (i nie chcesz mieć) osobnego interpretera Pythona, to następującą wersję

Kod: Zaznacz cały

# coding: utf-8

import os

# indeksy magiczne szablonów okien dialogowych
FILEOPEN_SIMPLE = 0
FILESAVE_SIMPLE = 1

def OOoFileDialog(ctx, fname, title, mode):
    picker = ctx.ServiceManager.createInstanceWithContext("com.sun.star.ui.dialogs.FilePicker", ctx)
    picker.initialize( (mode, ) )
    picker.setDisplayDirectory("file://" + fname)
    picker.setTitle(title)
    if picker.execute():
        fname = picker.getFiles()[0][7:]
    else:
        fname = None
    picker.dispose()
    return fname

def konwertuj():
        ctx = XSCRIPTCONTEXT.getComponentContext()
        nazwapliku = OOoFileDialog(ctx, os.getcwd(), u'Czytaj z pliku', FILEOPEN_SIMPLE)
        if not nazwapliku:
                exit()
        separator = '@'
        kategorie = set([])
        items = []
        plik = open(nazwapliku)
        for item in plik.readlines():
                if item[0] == item[-2] == '"':
                        item = item[1:-2]
                item = item.split(separator)
                item = [x.split(':') for x in item]
                item = dict(item)
                kategorie.update(item.keys())
                items.append(item)
        plik.close()

        nazwapliku = OOoFileDialog(ctx, nazwapliku, u'Zapisz do pliku', FILESAVE_SIMPLE)
        if not nazwapliku:
                exit()
        separator = '\t'
        kategorie = tuple(kategorie)
        plik = open(nazwapliku, 'w')
        plik.write(separator.join(kategorie) + '\n')
        for item in items:
                output = []
                for kat in kategorie:
                        try:
                                output.append(item[kat].strip())
                        except:
                                output.append('')
                plik.write(separator.join(output) + '\n')
        plik.close()
możesz wywołać jako makro OpenOffice, po umieszczeniu pliku z kodem w podkatalogu user/Scripts/python/ konfiguracji osobistej OpenOffice. Wywołanie za pomocą Narzędzia/Makra/Zarządzaj/Python/Moje makra/nazwa pliiku/[+]konwertuj/Uruchom.
W tej wersji program pyta o nazwy plików: wejściowego i wynikowego (uważaj, żeby nie nadpisać wejścia wynikami). Nie użyłem w niej wyrażenia with ze względu na nieco starszą wersję języka, jaka jest wbudowana w OpenOffice.

Testowałem na Twoich danych zakładając, że wszystkie rekordy są podobnie zbudowane (i bez błędów); nie mogę wziąć odpowiedzialności poprawność wyników, kiedy założenia te nie są spełnione.

Powstały plik tekstowy wczytasz do Calca standardową metodą. Wersji drugiej niewiele brakuje, by wyniki umieścić od razu w skoroszycie.
JJ
LO (24.2|7.6) ∙ Python (3.12|3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
ODPOWIEDZ