Automatisches Zeileneinfügen in einem Kalender möglich?

Moin,

in einer Tabelle möchte ich gerne automatisch fehlende Zeilen/Leerzeilen eintragen. Es sind Notizen zu Kalendertagen in Zeilen, aber fehlende Tage sollen eine neue, leere Zeile erhalten. Das sieht so aus:

Mo, 1.Jan
Di, 2.Jan
Do, 4.Jan
So, 7.Jan

soll werden zu:

Mo, 1.Jan
Di, 2.Jan

Do, 4.Jan
-hier sind zwei Leerzeilen
-hier sind zwei Leerzeilen
So, 7.Jan

geht sowas ohne riesige Verrenkungen?
Anstatt der Datumsangabe, kann man natürlich auch eine fortlaufende Zahl nehme:

44562
44563
44565
44568

Als Programm stehen mir Libreoffice 7.1.7.2 zur Verfügung und ggf irgendein nicht ganz altes MS Excel.

Danke für Hilfe und VG!
J~

namd,

Wäre ein Skript einsetzbar?

grüße
lipi

klar, wenn du mir sagst wie und welches :slight_smile:
Wobei mir da einfällt, dass die Lösung gar nicht auf eine Tabellenkalkulation beschränkt ist. Mit ‚sed‘ unter Linux können manche Leute ja auch wahre Wunder begehen - ich könnte das allerdings lediglich anwenden :slight_smile:

Wobei mir da einfällt, dass die Lösung gar nicht auf eine Tabellenkalkulation beschränkt ist. Mit ‚sed‘ unter Linux können manche Leute ja auch wahre Wunder begehen - ich könnte das allerdings lediglich anwenden :slight_smile:

Wenn ich also zB eine neue Spalte mit allen aufsteigenden Zahlen die ich haben will erzeuge müsste das Script den Inhalt der tatsächlichen Zeile „nur noch“ in die richtige Zeile einsortieren :slight_smile:
Das sähe dann so aus:

44562 - Inhalt44562
44563 - Inhalt44563
44565 - Inhalt44565
44568 - Inhalt44568

=>

44562 - Inhalt44562
44563 - Inhalt44563
44564
44565 - Inhalt44565
44566
44567
44568 - Inhalt44568

VG!
J~

moin,

Ich bin mir noch nicht ganz über den Verwendungszweck sicher. Daran sollte sich die Lösung ja etwas orientieren, damit es auch nutzbar ist.

Excelintern: ein 2. Blatt mit dem Startdatum in A1 und nach unten gefüllt reicht auch schon, um dann die Inhalte passend zum Datum zu suchen und zu übernehmen.

Für einmaligen gebrauch wäre es am schnellsten.
Für regelmäßigen gebrauch ist das nervig.
Hat man aber mehrere oder regelmäßige Listen die vielleicht auch logisch inkorrekt sein könnten, wäre eine VBA-Lösung sicher besser.

grüße
lipi

1 Like

Moin,

die Antwort fasse ich mal hier zusammen, damit alles beieinander bleibt und es es ja auch eine „Office-Lösung“ wurde.


@littlepinguin ich kann nur mit offenem Mund stauen, es hat so funktioniert mit deinem Script.
Ich bin dir zu tiefstem Dank verpflichtet! :slight_smile:

Sogar ein Problem, dass ich noch gar nicht ansprach und welches ich „zu Fuß“ lösen wollten hat das Script nicht aus dem Tritt gebracht. Einige, wenige Einträge hatten nämlich kein Datum in der Datumsspalte eingetragen, befanden sich aber in der richtigen Zeile. Diese wurden nicht verschoben und es wurde auch keine zusätzliche Zeile erzeugt, juhu!

Noch mal fürs Protokoll, was ich konkret gemacht habe:

  • LibreOffice 7.1.7.2
  • die Kopfzeilen habe ich entfernt und temporär in eine andere Tabelle ausgelagert, so dass in Zelle A1 das erste Datum stand usw.
  • Extras -> Makros -> Makros bearbeiten
  • in das Programmierfeld unter „REM ***** BASIC *****“ u.g. Script eingefügt, die Zahl 400 auf 800 erhöht weil mein fertiger Kalender gute 2 Jahre umfasst was bummelig 800 Zeilen sind und direkt mit dem Playknopf ausgeführt
  • Kopfzeilen wieder zurück gebracht
  • zur Kontrolle in einer neu erstellten Spalte das passende Datum in A1 eingetragen und mit der Maus „runter gezogen“ zum ausfüllen
  • zur Kontrolle in einer neu erstellten Spalte die Datumsdifferenz zwischen selbst und vom Script erzeugten Datumswert ausgerechnet (muss natürlich immer 0 sein wenn korrekt)
  • beim überfliegen habe ich bis jetzt keinen Fehler entdeckt

feddich :slight_smile:

OK, diesen Fehler hatte ich nicht, aber versuche dran zu denken wenn ich das Script noch mal einsetze.

Die 400 einfach der Länge der fertigen Tabelle anpassen. Wenn das regelmäßig eingesetzt wird, könnte man das mit 1-2 Zeilen mehr noch alles bissl schöner machen.

Das war kein Problem das eben von Hand zu ändern. Das Script ist super so wie es ist. :slight_smile:
Allerdings habe ich wirklich NULL Ahnung von VBA und weiß überhaupt nicht was es gemacht hat.
Nur wenn du magst könntest du dazu kurz was schreiben, danke schön!

Ich bin mir noch nicht ganz über den Verwendungszweck sicher. Daran sollte sich die Lösung ja etwas orientieren, damit es auch nutzbar ist.

Es ist einfach ein Kalender/Tagebuch mit Einträgen, aber nicht an jedem Tag. Es soll mit einem anderen, vollständigen Kalender zusammen geführt werden.

Excelintern: ein 2. Blatt mit dem Startdatum in A1 und nach unten gefüllt reicht auch schon, um dann die Inhalte passend zum Datum zu suchen und zu übernehmen.
Für einmaligen gebrauch wäre es am schnellsten.

Ja, aber es sind über zwei Jahre und entsprechend viele Zeilen :wink:

Nochmals vielen Dank!

J~


Das Script von @littlepinguin

Sub Main
Dim alt as long
Dim b as long
Dim i
alt = ThisComponent.Sheets(0).getCellByPosition(0,0).value
for i = 1 to 400
 b = ThisComponent.Sheets(0).getCellByPosition(0,i).value
 if b<>0 then
  if alt+1<b then
    ThisComponent.Sheets(0).Rows.insertByIndex(i,b-alt-1)
  end if
  alt=b
 else
  alt=alt+1
 end if
Next i

End Sub

Moin,

Vorab: Jeder der programmieren kann, wird zurecht den Kopf schütteln. Darauf soll es bitte nicht ankommen.

Es ist etwas ausführlicher geworden als erwartet. Zum verstehen was passiert hilft es mir jedoch immer, das Programm möglichst weit zu zerlegen.
Abkürzen überlass ich lieber Denjenigen, die es können.

das macht meist nix, denn der prinzipielle Aufbau ist nahezu immer gleich.
Daher keinen Kopf machen, wie das exakt aussehen muss, das kann man googlen.

Den Rest versteht man imo auch, wenn man mit Excel arbeitet und ein paar Formeln erstellt hat.
Man muss sich dabei nur klar werden, dass man sich in keiner Zelle mehr befindet.

Frei wie man also ist, muss du dir klar sein, dass du keinen Ausgangspunkt hast. Keine Zelle, nicht mal ein Arbeitsblatt.
Nur eine Arbeitsanweisung die abgearbeitet wird.

Und (ganz wichtig) der Arbeiter ist stur und dumm. Es wird exakt das gemacht, was im Programm steht und sei es noch so dämlich.

Dim überspringen wir, das fällt unter lästige Pflicht und ist nur dazu da um alt, b und i als Variablen nutzen zu dürfen.

Hier eine kurze Theorie: 1 ist nicht die erste Zahl beim Zählen, sondern 0.
Ebenso sollte man im Hinterkopf behalten, dass 0 damit eine Zahl ist die einen Wert hat - der eben 0 ist.

Dann der Objektmist. Im Grunde kennst du das auch aus Excel. Wir fangen bei der Zeile hinten an:
ThisComponent.Sheets(0).getCellByPosition(0,0).value
also .value
Da holst du dir mit A1 den Wert der Zelle.
In der Tabelle selbst genügt es, die Zelle mit A1 anzusprechen und es wird direkt der Wert zurück gegeben (weil mehr eben nicht geht).
In VBA reicht das nicht. Hier muss explizit angegeben werden, dass man den Wert möchte. Daneben gibt es zB. noch .formula was die Formel der Zelle liefert und auch die Farben und Schriftarten, -größen müssen irgendwie ansprechbar sein.
Das nur zum groben Verständnis, warum .value nötig ist…

Zurück zum Wert der Zelle. Davor muss die Zelle also ausgewählt werden.
.getCellByPosition(0,0)
Erklärung erübrigt sich vermutlich. Zelle bei der Position 0,0. Wie gesagt: A ist nicht 1 sondern 0. Daraus folgt dann leider auch, dass Zeile 1 an der Position 0 liegt.
Gewöhnt man sich irgendwann dran.

Will man das umgehen, könnte man die Zelle auch anders ansprechen, etwa mit .getCellByName("A1")
Wäre bei dem Problem jetzt egal, sieht aber nicht so schön aus und wir würden das Thema noch um den Umgang mit Text erweitern.

.Sheet(0) erklärt sich vermutlich auch von selbst. 0 ist wieder das erste Blatt.
ThisComponent ist eben das aktuelle Dokument.

Daraus ergibt sich dann: alt = in dem Dokument, im Blatt 1, in Zelle 0,0 den Wert
Nun haben wir das Datum (als Zahl 44562) in der Variablen alt hinterlegt.

For - gibt es immer und überall. Lernt man schnell, weil man es braucht.
for i = 1 to 400
kann man auch normal lesen: von 1 bis 400 mach das…

b = ThisComponent.Sheets(0).getCellByPosition(0,i).value
Nächste Zeile kennen wir schon, b bekommt also den Wert von A2 (weil i = 1 ist, und damit 0,1 der Zelle A2 entspricht)

if b<>0 then
Schönes Beispiel dafür, dass es kein Problem ist, wenn man VBA nicht kann.
ich durfte hier lernen, dass VBA mit != nicht klar kommt, und dass mit end if abgeschlossen wird.
Excelangelehnt ist das nichts weiter als wenn(das, dann, sonst)

Es wird also nur geprüft, ob b nicht 0 ist, was einer leeren Zelle entsprechen würde.
Was bei WENN() die Klammer, ist bei IF-Then-Else das End If
Wir befinden uns also weiterhin innerhalb.
(Das kann je nach Programmiersprache anders aussehen, das Prinzip bleibt aber gleich.)

if alt+1<b then
Es wird geprüft, ob das erste Datum was in alt abgelegt ist plus einen Tag kleiner ist, als das Datum der aktuellen Zelle in b.
Wenn das so wäre, fehlt mindestens Tag.

Fehlt mindestens ein Tag, muss also eine leere Zeile rein.
ThisComponent.Sheets(0).Rows.insertByIndex(Position, Anzahl)
ich denke, das erklärt sich auch fast von selbst.

Die Position der Zeile kennen wir, das ist gleich der Variablen i.
Die Anzahl kennen wir auch, die ermittelt sich auch der Differenz beider Datumsangaben abzüglich 1 - logisch, um 1 muss das Datum ja steigen.

Übersichtlicher weise mal nur die Tage:
Zwischen dem 22. aus Zelle A2 und dem 20. aus A1 fehlt also 1 Tag. (22-20-1)

Dann das erste End if zum schließen der IF-Anweisung
Damit sind wir wieder innerhalb der Ersten und soweit fertig.
Wir weisen das aktuell geprüfte Datum nun der Variablen alt zu, um den nächsten Durchlauf vorzubereiten.
Der Inhalt von A2 steht nun in alt

Else
anders als bei Wenn(Bedingung,then,else) ist das optional und bezieht sich auf die Prüfung ob b<>0 ist.

wenn b also 0 war und kein Datum enthält, zählen wir eben in Kopf weiter.
Der Wert von alt wird um eins erhöht.
alt ist also alt + 1

Danach ist auch diese IF-Geschichte zu Ende und es wurde erfolgreich eine Zeile, oder mehrere wenn nötig, eingefügt.

Next i
wir springen wieder hoch in die For-Schleife. Dabei erhöht sich i um 1
i ist nun also 2.

Ausgelesen und in b abgelegt wird daher der Wert der Zelle an Position 0,2 - Was A3 entspricht. alt haben wir bereits angepasst und den Wert aus A2 zugewiesen.

Und so läuft das nun die 400 oder 800 mal durch.
(Hat mich jedoch selbst gestört, bevor ich es wieder gelöscht hab, ist das noch ne hübschere while-Schleife geworden.)

Wenn das Prinzip klar ist, ist es imo egal, ob man VBA oder C++ kann oder eben nicht.
Es dauert nur länger, es wird sicher auch komplizierter als nötig und man muss Google öfter bemühen.
Hat man aber eine grobe Ahnung was man sucht, dann findet man auch eine Lösung - nur vielleicht nicht die Optimale.

Bei sowas ist dann oft der Weg das Ziel.

grüße
lipi

1 Like

super, noch ein zweites Mal herzlichen Dank für deine genauen Erläuterungen!
Wenn ich nur eine kleine Veränderung am Script benötige, würde ich es jetzt vielleicht sogar selbst hinbekommen :slight_smile:
Aber noch eine Frage:
Wenn ich weiß, ich brauche einen Befehl der eine Zeile einfügt (war hier ja Rows.insertByIndex(Position, Anzahl) ) wie finde ich den?
Gibt es eine kommentierte Liste aller VBA-Befehle die man einfach nach dem Stichworten „Zeile einfügen o.ä.“ durchsuchen kann?

VG!
J~

Der Vollständigkeit halber möchte ich hier auch erwähnen, dass hroptatyr
eine awk/mawk-Lösung hat (habe ich aber noch nicht ausprobiert).

awk '{if (i==$1){print;i++}else if(i){for (;i < $1;i++) {print i};print;i++}else{i=$1+1;print}}' DATEI

hi,

es gibt Entwicklerumgebungen, die dir die Möglichkeiten dann schon zeigen.
Da ich VBA aber so gar nicht kann und sogar schauen muss, wie genau for und if auszusehen hat, nutze ich immer schnell Google ala „insert row openoffice vba“ oder ähnlichem.
Ich such mir bei fast allem lieber Beispiele, weil man dann auch mal bissl was drum herum sieht und versteht.

Wenn man Größeres vor hat, findet man sich so eigentlich immer irgendwie rein.

Kleiner Hinweis, wenn’s schon ums verstehen geht (und weil ichs selbst verstehen wollte und nix zutun habe):

Zusammenfassung

$1 entspricht dem ersten ‚Wort‘ der Zeile, $2 dem Zweitem usw.
print solo gilt wie print $0 und gibt diese Zeile ohne Veränderung aus.
Generell wird jede Zeile eingelesen und dann einmal das Script abgearbeitet.

{
  if (i==$1){
    print
    i++
  }
  else if(i){
    for (;i < $1;i++) {
        print i
     };
    print;
    i++
  }
  else {
    i=$1+1;
    print
  }
}

grüße
lipi

1 Like