[gelöst] Perl: Brauche Hilfe bei txt2tex Script

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

[gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 02.06.2018 22:06:33

Ich schreibe gerne Texte (bis 1-8 A4-Seiten) in vim als .txt Datei. Dabei habe ich eine maximale Zeilenlänge von 79 Zeichen. (Danach fügt vim ein Newline-Zeichen an und es geht in der nächsten Zeile weiter.)

Anschließend konvertiere ich die .txt in eine .tex Datei (ich mag Texte aus verschiedenen Gründen nicht gleich als .tex-Datei schreiben). Dabei füge ich dann immer "\\" ein, wenn newline erhalten bleiben soll, usw.

Nun habe ich mich endlich dazu durchgerungen, das zu automatisieren, also ein Script zu schreiben, welches für mich - zumindest grob - die Formatierung übernimmt.
Aufgaben:
1. .txt Datei in eine gleichnamige .tex Datei kopieren (und letztere dabei erstellen).
2. Alle leeren Zeilen mit "\\" füllen.
3. Bei jeder Zeile, die mit Punkt oder Doppelpunkt endet, prüfen, ob das erste Wort der nächsten Zeile noch hingepasst hätte (bei einer Zeilenlänge von 79 Zeichen). Wenn ja, annehmen, dass dieser Zeilenumbruch gewollt ist und "\\" anfügen.
Das ist natürlich nicht perfekt, deckt aber häufige Fälle ab und erleichtert mir die Arbeit.

Also habe ich da mal was in Perl verfasst. Das füllt aber leider nur die leeren Zeilen mit "\\". Die anderen Fälle werden nicht abgedeckt, obwohl ich mir einbilde, das so programmiert zu haben. Mag vielleicht jemand so freundlich sein und mir sagen, wo der Fehler in diesem Script ist?

Code: Alles auswählen

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
use Tie::File;
use utf8;

# input = filename. Append it to full path.
my $ofile = "$ENV{HOME}/Dokumente/@ARGV";

# exit if file is not a .txt file
if ($ofile !~ m/.txt$/) {
	die $!;
}

# build the name for the new .tex file by changing the suffix
my $file = $ofile =~ s/.txt$/.tex/r;

# copy the .txt file to a .tex file
copy($ofile,$file) or die $!;

# read file into an array
tie my @lines, 'Tie::File', $file or die $!;

# loop over the array (= file) line by line
for (my $i=0; $i<=$#lines; $i++) {
	# make programming easier
	my $line = $lines[$i];
	# if line is empty, insert "\\"
	if ($line eq "") {
		$lines[$i] =~ s/^$/\\\\/g;
		next;
	}
	# if line do not end with "." or ":", we jump to next iteration
	if ($line !~ m/\.$/ || $line !~ m/\:$/) {
		next;
	}
	# get length of line
	my $llen = length($line);
	# if the line is 79 chars long, we jump to next iteration
	if ($llen == 79) {
		next;
	}
	# get next line
	my $nline = $lines[$i+1];
	# get first word of next line
	my $nword = $nline =~ s/ .*//r;
	# get length of this word
	my $nwlen = length($nword);

	# check if space after $line is longer than length of $nword
	# if so, we insert "\\" after the last "." or ":" of $line
	# because we assume that the linebreak is intended.
	if (79-$llen > $nwlen) {
		if ($line =~ m/\.$/) {
			$lines[$i] =~ s/\.$/\.\\\\/;
		} else {
			$lines[$i] =~ s/\:$/\:\\\\/;
		}
	}
}
Zuletzt geändert von RobertDebiannutzer am 03.06.2018 14:17:03, insgesamt 1-mal geändert.

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

[gelöst] Re: Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 03.06.2018 14:16:50

Ich hab's schon. Ich habe mich hier verdusselt:

Code: Alles auswählen

	# if line do not end with "." or ":", we jump to next iteration
	if ($line !~ m/\.$/ || $line !~ m/\:$/) {
		next;
	}
Angenommen, die Zeile endet mit Punkt. Dann trifft die erste Bedingung nicht zu. So weit, so gut. Aber dann bewahrheitet sich die zweite... :facepalm: :facepalm:

Korrigiert:

Code: Alles auswählen

	# if line does not end with "." or ":", jump to next iteration
	if ($line !~ m/\.$/ && $line !~ m/\:$/) {
		next;
	}
Und nachdem es nun überhaupt funktionierte, fiel mir noch auf, dass ich vergessen hatte, den loop in der letzten Zeile der Datei (des arrays) zu beenden (für die es ja logischerweise keine Folgezeile mehr gibt).

Jetzt funktioniert jedenfalls alles. Wen es interessiert, hier nochmal die vollständige (und nun funktionsfähige) Version:

Code: Alles auswählen

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
use Tie::File;
use utf8;

# input = filename. Append it to full path.
my $ofile = "$ENV{HOME}/Dokumente/@ARGV";

# exit if file is not a .txt file
if ($ofile !~ m/.txt$/) {
	die $!;
}

# build the name for the new .tex file by changing the suffix
my $file = $ofile =~ s/.txt$/.tex/r;

# copy the .txt file to a .tex file
copy($ofile,$file) or die $!;

# read file into an array
tie my @lines, 'Tie::File', $file or die $!;

# loop over the array (= file) line by line
for (my $i=0; $i<=$#lines; $i++) {
	# if last line, exit loop
	if ($i == $#lines) {
		last;
	}
	# make programming easier
	my $line = $lines[$i];
	# if line is empty, insert "\\"
	if ($line eq "") {
		$lines[$i] =~ s/^$/\\\\/g;
		next;
	}
	# if line does not end with "." or ":", jump to next iteration
	if ($line !~ m/\.$/ && $line !~ m/\:$/) {
		next;
	}
	# get length of line
	my $llen = length($line);
	# if the line is 79 chars long, jump to next iteration
	if ($llen == 79) {
		next;
	}
	# get next line
	my $nline = $lines[$i+1];
	# get first word of next line
	my $nword = $nline =~ s/ .*//r;
	# get length of this word
	my $nwlen = length($nword);

	# check if space after $line is longer than length of $nword
	# if so, insert "\\" after the last "." or ":" of $line
	# because we assume that the linebreak is intended.
	if (79-$llen > $nwlen) {
		if ($line =~ m/\.$/) {
			$lines[$i] =~ s/\.$/\.\\\\/;
		} else {
			$lines[$i] =~ s/\:$/\:\\\\/;
		}
	}
}

eggy
Beiträge: 3334
Registriert: 10.05.2008 11:23:50

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von eggy » 03.06.2018 18:07:21

Darf ich mal fragen, warum du das mit 79 Zeichen machst?
Kennst Du den Befehl fmt?

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 03.06.2018 18:43:26

79 Zeichen Zeilenlänge habe ich, weil das die Standardeinstellung von vim ist. :D Außerdem passt mir das ganz gut so. Ich habe mir extra für Texte noch zusätzlich gvim installiert und dort ein spezielles Layout eingerichtet. D.h. (grob):
1. alle gui-Elemente entfernt
2. vim in drei Fenster geteilt, im mittleren Fenster befindet sich die zu bearbeitende Datei
3. Die Trennwände unsichtbar gemacht
4. Die Tilden als Platzhalter für leere Zeilen unsichtbar gemacht
5. Fokus beim Start automatisch auf mittleren vim-Fenster
6. Das linke vim-Fenster stellt automatisch eine Datei bereit, die den gleichen Namen trägt wie die Haupt-Datei, aber mit der Endung ".meta". Die dient für Notizen während des Schreibens. Wird da nichts reingeschrieben, wird sie beim schließen von vim gar nicht erst gespeichert.

Im Normalfall befindet sich also einfach mein Text mitten auf dem Bildschirm, bis 79 Zeichen breit, und sonst nichts anderes! Ok, die minimale Titelleiste von i3, die minimale Statusleiste von i3blocks und das "-- INSERT --" von vim, aber ansonsten ist der Bildschirm bis auf den Text ganz leer. :THX:
Vim reformatiert dann dynamisch den Text. D.h., wenn ich schreibe, springt mein Cursor ab Erreichen der maximalen Zeilenlänge automatisch in die nächste Zeile. Füge ich nachträglich Text ein, wird alles in realtime automatisch wieder reformatiert.

Nur irgendwann ist der Text fertig und dann will ich das ganze in latex umwandeln. Dazu muss ich dann immer, wenn ich einen Zeilenumbruch erhalten will, "\\" einfügen. Und natürlich den Latex-Header sowie \begin{document} und \end{document} - das habe ich in meinem Perl script mittels unshift und push auch noch ergänzt.
Wenn ich dann die .tex-Datei habe, kann ich sie gemütlich mittels vim-Befehl zum PDF kompilieren und bin glücklich. (Denn latex nimmt mir dabei auch noch Trennungen und Seitenzahlen ab.)

Ursprünglich wollte ich die automatisierte Umwandlung als bash-Script verfassen und mein bisheriges Lieblingswerkzeug sed verwenden. Doch sed hatte Probleme mit den Sonderzeichen in den Zeilen der Datei. Nun hat sich glaube ich Perl zu meinem Lieblingswerkzeug gemausert... :THX:
Diese Sprache eröffnet mir ganz neue Möglichkeiten und ist in so einem Fall wie diesem wirklich total einfach zu bedienen!

tobo
Beiträge: 2338
Registriert: 10.12.2008 10:51:41

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von tobo » 03.06.2018 19:50:22

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
03.06.2018 18:43:26
Ich habe mir extra für Texte noch zusätzlich gvim installiert und dort ein spezielles Layout eingerichtet. D.h. (grob):
1. alle gui-Elemente entfernt
Vielleicht verstehe ich das alles auch nicht so richtig, aber da sehe ich denselben Sinn drin, wie wenn man newlines speziell kennzeichnet, damit man sie wieder entfernen kann!?
Zunächst mal fügt man nur die newlines ein, die da hingehören und überlässt die Darstellung dem Leser. Es käme ja auch niemand auf die Idee 30-Zeichen-breite-E-Mails zu verschicken, nur weil man das so besser findet So lange der Satz/Absatz eben ist, solange ist eben auch kein Umbruch. Die Darstellung beim Leser ist dann halt nach dessen Gusto (60, 70, 80, etc.) Zeichen. So wie er es haben will.
In den verschieden Vims, gibt's ja verschiedene Möglichkeiten (linebreak, wrap, etc.) um die Darstellung zu ändern. Da wird dann der Text für dich in der Ansicht umgebrochen, es wird aber kein newline eingefügt. Es ändert sich also nur die Darstellung des Textes und nicht der Text.

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 03.06.2018 20:31:22

Ja, ist ein bisschen kompliziert.

Also gvim habe ich zusätzlich installiert, damit diese ganzen Spezial-Einstellungen in .vimrc nicht auch für "normal-vim" gelten.*

Das mit den newlines - die ich übrigens doch gar nicht entferne - ist halt so eine Sache. Deine Aussage
tobo hat geschrieben: ↑ zum Beitrag ↑
03.06.2018 19:50:22
Da wird dann der Text für dich in der Ansicht umgebrochen, es wird aber kein newline eingefügt. Es ändert sich also nur die Darstellung des Textes und nicht der Text.
ist AFAIK nicht richtig, oder ich war zu doof, das so einzustellen.*
Nebenbei braucht latex AFAIK sowieso die "\\" um den Zeilenumbruch als solchen zu erkennen. Alle anderen Zeilenumbrüche werden eh ignoriert.
Und wenn ich das Ganze dann zum PDF mache, ist eh alles klar. Die andere Seite liest dann das PDF so wie jedes PDF. Da kommt eh keine .txt-Datei an.

*Ich habe in .vimrc u.a.:

Code: Alles auswählen

if has("gui_running")
  set guicursor+=a:blinkon0
  set guifont=Hack\ 12
  set guioptions-=m  "remove menu bar
  set guioptions-=T  "remove toolbar
  set guioptions-=r  "remove right-hand scroll bar
  set guioptions-=l  "remove left-hand scroll bar
  set guioptions-=L  "remove left-hand scroll bar
  set spell
  set spelllang=de,en,fr
  set formatoptions+=wa
  set linebreak
  inoremap -- –
  ino " „”<left>
  ino ' ’
" syn match noSpellHyphenation "[a-zA-Zäöüß]*[^ ]-[^ ][a-zA-Zäöüß]*" contains=@NoSpell
  set spellcapcheck="[?!]\_[\])'" \t]\+")
  set printoptions=paper:A4,syntax:n,number:n,header:0,left:5pc,right:5pc,top:5pc,bottom:5pc
  set whichwrap+=<,>,[,]
  highlight EndOfBuffer guifg=Grey15
  set statusline=%=%l,%L\ \ \ \ \ \ \ \ \ \ \ \ \      " Note the whitespace!
  highlight StatusLine guibg=Grey15 guifg=Yellow
  highlight StatusLineNC guibg=Grey15 guifg=Grey15
  highlight VertSplit guibg=Grey15 guifg=Grey15
  command Q qa
Und aufgerufen wird das Ganze so:

Code: Alles auswählen

gvim -c"e $file" -c"vnew | e $(pwd)/$file.meta | vertical-resize 39 | setlocal textwidth=35" -c'exe 2 "wincmd w"' > /dev/null 2>&1 &
Nebenbei bin ich auch froh, bei der Gelegenheit Perl für mich entdeckt zu haben...

tobo
Beiträge: 2338
Registriert: 10.12.2008 10:51:41

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von tobo » 03.06.2018 23:09:20

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
03.06.2018 20:31:22
Also gvim habe ich zusätzlich installiert, damit diese ganzen Spezial-Einstellungen in .vimrc nicht auch für "normal-vim" gelten.
Man könnte die Konfigurationsdatei beim Start mittels vim -u <DATEI> angeben oder EXINIT entsprechend setzen.
Deine Aussage
tobo hat geschrieben: ↑ zum Beitrag ↑
03.06.2018 19:50:22
Da wird dann der Text für dich in der Ansicht umgebrochen, es wird aber kein newline eingefügt. Es ändert sich also nur die Darstellung des Textes und nicht der Text.
ist AFAIK nicht richtig, oder ich war zu doof, das so einzustellen.
Steht in Abhängigkeit zu wrap, linebreak und columns, was wiederum in Abhängigkeit zur Fensterbreite steht. Per ex-Kommando

Code: Alles auswählen

:set wrap linebreak
und dann vim im i3 floating mode mit

Code: Alles auswählen

:set columns=79
oder im i3 tiling mode mittels $mod-r auf

Code: Alles auswählen

:set columns?
79 einstellen. Das wäre jetzt gedacht für 3 nebeneinander liegende vim-Instanzen. Falls du das aber so meinst, dass bei dir nur eine Instanz läuft und dort gesplittet wurde, dann in die Mitte wechseln und

Code: Alles auswählen

:vertical resize 79
ausführen. Das sollte dann mehr oder weniger aufs gleiche rauslaufen!?

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 04.06.2018 09:09:10

Oh, das mit der Konfigurationsdatei ist ein guter Hinweis, danke!

tobo hat geschrieben: ↑ zum Beitrag ↑
03.06.2018 23:09:20
Falls du das aber so meinst, dass bei dir nur eine Instanz läuft und dort gesplittet wurde
Ja, so mache ich das...

Dein Vorschlag bezüglich Textformatierung funktioniert, aber dann - ich erinnere mich auch wieder, dass das damals mein Problem war - wird eine umgebrochene Zeile als eine Zeile angesehen und ich kann mit den Hoch- und Runter-Pfeiltasten nicht mehr von Zeile zu Zeile hüpfen. Da gibt's zwar - soweit ich mich recht erinnere - irgendeinen workaround (remapping), aber das ist mir zu kompliziert. Da gefallen mir meine vim-Einstellungen besser, bei denen eine (mehrmals) umgebrochene Zeile als mehrere Zeilen interpretiert wird und ich es so bearbeiten kann wie z.B. hier im Forum in der Textbox.

Latex ist es ja eh egal, ob da Zeilenumbrüche sind oder nicht, denn es aktzeptiert ja sowieso nur zwei "\" oder ein "\par" als Zeilenumbruch.

tobo
Beiträge: 2338
Registriert: 10.12.2008 10:51:41

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von tobo » 04.06.2018 12:09:34

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
04.06.2018 09:09:10
wird eine umgebrochene Zeile als eine Zeile angesehen und ich kann mit den Hoch- und Runter-Pfeiltasten nicht mehr von Zeile zu Zeile hüpfen. Da gibt's zwar - soweit ich mich recht erinnere - irgendeinen workaround (remapping), aber das ist mir zu kompliziert.
j/k = Zeile runter/hoch
gj/gk = Bildschirmzeile runter/hoch
Und das funktioniert auch für Pfeiltastenbenutzer mit vorangestelltem g.

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: [gelöst] Perl: Brauche Hilfe bei txt2tex Script

Beitrag von RobertDebiannutzer » 04.06.2018 13:59:24

Ja, muss man remappen, sonst funktioniert das nicht im Insert-Modus. Und leider funktioniert dann zwar das hüpfen von Zeile zu Zeile, aber wenn dadurch der Text nach oben oder unten verschoben wird, ist das immer noch Zeilenweise (also nicht Bildschirmzeilenweise), also ruckelig.
Aber wie gesagt: Ist ja nicht schlimm, wenn ich unnötige linebreaks habe. Schreiben funktioniert so wie ich es brauche, latex kümmert sich nicht drum und im pdf ist es dann eh so, wie latex es macht.

Antworten