Parser für Smallcaps

Redefinition von Makros, Definition eigener Befehle sowie neuer Umgebungen


keth-tex

Parser für Smallcaps

Beitrag von keth-tex »

Ich möchte bestimmte Überschriften, welche im Stil

\bfseries\sffamily

formatiert sind, als Smallcaps setzen. Eine solche Kombination ist für die gewünschte Schriftart nicht verfügbar. Auch nicht durch Zusatz-Pakete. Ich habe es dann erst einmal "manuell" umgesetzt, indem ich bei den entsprechenden Anfangsbuchstaben die Schriftgröße eine Stufe hoch- und danach wieder runtergesetzt habe. Ich weiß, dass ist ein "übler Hack" und nicht empfehlenswert. Aber es sieht in diesem Fall wirklich sehr vernünftig aus. Da ich es an einigen Stellen benötige und so etwas auch gerne zentral definieren und nicht einfach an den Stellen "hart reincodieren" möchte, frage ich mich, ob es theoretisch möglich wäre, einen Parser zu schreiben, welcher einen String wie "Salz und Pfeffer" beispielsweise in

\large S\normalsize ALZ UND \large P\normalsize FEFFER

verwandelt...?

Danke schon mal für jegliche hilfreiche Antworten!


MoeWe
Forum-Meister
Forum-Meister
Beiträge: 801
Registriert: Fr 30. Aug 2019, 15:35
Kontaktdaten:

Re: Parser für Smallcaps

Beitrag von MoeWe »

Ich behaupte ja immer, dass LaTeX nicht für Stringmanipulation geeignet ist, aber expl3 bietet schon einige Möglichkeiten. So können wir mit RegExps nach Großbuchstaben suchen und mit l3text auch ALL-CAPS bekommen. Zusammen mit relsize (mit dem wir die Schriftgröße relativ ändern können) ergibt sich

\documentclass[ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{expl3,xparse}
\usepackage{relsize}

\ExplSyntaxOn
\tl_new:N \l_keth_text_tl

\cs_generate_variant:Nn \text_uppercase:n {o}

\NewDocumentCommand{\textfakesc}{m}
  {
    \tl_set:Nn \l_keth_text_tl {#1}
    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl
    \text_uppercase:o \l_keth_text_tl
  }
\ExplSyntaxOff


\begin{document}
{\sffamily\bfseries\textfakesc{Ello, me Dearios}}

{\sffamily\bfseries\textsc{Ello, me Dearios}}

{\Large\sffamily\bfseries\textfakesc{Ello, me Dearios}\par}
\end{document}

Leider habe ich keine Möglichkeit gefunden, im RegExp nach allen Großbuchstaben zu suchen (die POSIX-Klasse [:upper:] kann nur A-Z und \p steht noch auf der To-Do-Liste), daher die hartcodierte Liste A-ZÄÖÜ.


keth-tex

Re: Parser für Smallcaps

Beitrag von keth-tex »

Wow. Vielen Dank! Das ist ja eine super Lösung, da sie sich ganz flexibel auf verschiedenste Schriftgrößen anwenden lässt...

Was ich vielleicht gleich hätte dazu sagen sollen: Eigentlich benötige ich das Ganze hauptsächlich für part-Einträge im Inhaltsverzeichnis. Da habe ich jetzt noch ein kleines Problem mit hyperref bzw. bookmark: Eigentlich wollte ich die part-Einträge in den Lesezeichen gerne all-caps haben, damit da mehr Struktur drin ist. Ein \MakeUppercase möchte hyperref aber scheinbar überhaupt nicht haben...
Gibt es evtl. irgendeine Möglichkeit nach all-caps zu parsen und das Ergebnis an hyperref zu übergeben, bspw. mittels \texorpdfstring?


MoeWe
Forum-Meister
Forum-Meister
Beiträge: 801
Registriert: Fr 30. Aug 2019, 15:35
Kontaktdaten:

Re: Parser für Smallcaps

Beitrag von MoeWe »

Ohne ordentliches Minimalbeispiel, das den gewünschten Einsatz zeigt, kann ich natürlich nur spekulieren. Es ist aber recht einfach, hier \texorpdfstring zu nutzen. Ob Dir das hilft, weiß ich aber nicht.

\documentclass[ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{expl3,xparse}
\usepackage{relsize}
\usepackage{hyperref}

\ExplSyntaxOn
\tl_new:N \l_keth_text_tl

\cs_generate_variant:Nn \text_uppercase:n {o}

\NewDocumentCommand{\textfakesc}{m}
  {
    \tl_set:Nn \l_keth_text_tl {#1}
    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl
    \texorpdfstring{\text_uppercase:o \l_keth_text_tl}{#1}
  }
\ExplSyntaxOff


\begin{document}
{\sffamily\bfseries\textfakesc{Ello, me Dearios}}

{\sffamily\bfseries\textsc{Ello, me Dearios}}

{\Large\sffamily\bfseries\textfakesc{Ello, me Dearios}\par}
\end{document}

Copy-und-Paste funktioniert bei dem Text auch nicht richtig. Man könnte das was mit accsupp basteln, aber das wird nicht von jedem PDF-Betracher unterstützt.

\documentclass[ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{expl3,xparse}
\usepackage{relsize}
\usepackage{accsupp}
\usepackage{hyperref}

\ExplSyntaxOn
\tl_new:N \l_keth_text_tl

\cs_generate_variant:Nn \text_uppercase:n {o}

\NewDocumentCommand{\textfakesc}{m}
  {
    \tl_set:Nn \l_keth_text_tl {#1}
    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl
    \BeginAccSupp{method=escape,ActualText={#1}}%
    \texorpdfstring{\text_uppercase:o \l_keth_text_tl}{#1}
    \EndAccSupp{}
  }
\ExplSyntaxOff


\begin{document}
{\sffamily\bfseries\textfakesc{Ello, me Dearios}}

{\sffamily\bfseries\textsc{Ello, me Dearios}}

{\Large\sffamily\bfseries\textfakesc{Ello, me Dearios}\par}
\end{document}

keth-tex

Re: Parser für Smallcaps

Beitrag von keth-tex »

Bin mir nicht sicher, ob ich Dich richtig verstehe, aber ein Copy-Paste des mittels des Parsers erzeugten Textes funktioniert bei mir genauso gut wie beim übrigen Text. (Habe es zumindest mal für SumatraPDF, PDF.js und Adobe Reader getestet und konnte keinerlei Unterschied feststellen.)

In Bezug auf die eigentliche Nachfrage hast Du mich wohl falsch verstanden. Deine Lösung funktioniert super. Ich habe nur noch das Problem, wie ich sozusagen \MakeUppercase in Kombination mit hyperref verwenden kann. (Oder den Output des Parsers an hyperref übergeben kann.) Aktuell habe ich mit der Parser-Lösung in den bookmarks den Eintrag nicht in all-caps und müsste das quasi manuell eingeben. Was ich gerne erreichen würde, ist, dass ich im Dokument quasi nur noch etwas wie \specialpart{Ello, me Dearios} eingeben muss und nicht \specialpart{Ello, me Dearios}{ELLO, ME DEARIOS}. Dass also die fake-small-caps-Variante fürs toc und die all-caps-Variante für die bookmarks von den Definitionen in der Präambel bzw. Klassen-Datei erzeugt werden.

Dies ist im Prinzip ein Beispiel für die "Lösung", die ich momentan verwende:

\documentclass[headings=optiontotoc,paper=a5,10pt]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{xcolor}
\usepackage{microtype}
\usepackage{hyperref}
\usepackage{bookmark}

\linespread{1.05}

\renewcommand*{\raggedsection}{\centering}

% for centering part toc entry:
\makeatletter
\newcommand*{\specialparttocentryformat}[1]{%
    \large\bfseries\sffamily%
    \let\numberline@box\mbox%
    \def\autodot{: }%
    \centering%
    #1%
}
\RedeclareSectionCommand[tocnumwidth=0pt,tocindent=0pt,tocentryformat=\specialparttocentryformat,toclinefill={},tocpagenumberbox=\@gobble,tocpagenumberwidth=0pt,tocrightindent=0pt,tocraggedpagenumber]{part}
\makeatother

\newcommand*{\up}{\large}
\newcommand*{\down}{\normalsize}
\newcommand*{\muc}[1]{\MakeUppercase{#1}}

\newcommand*{\bookonetoc}{\up E\down RSTES \up B\down UCH}
\newcommand*{\bookonetopictoc}{\up E\down LLO, ME \up D\down EARIOS}
\newcommand*{\partonetoc}{\up E\down RSTER \up T\down EIL}
\newcommand*{\partonetopictoc}{\up E\down LLO, ME \up D\down EARIOS}

\newcommand*{\dlb}{\\\vspace{\baselineskip}}% double line break
\newcommand*{\tlb}{\\\vspace{2\baselineskip}}% triple line break
\newcommand*{\lbtoc}{\texorpdfstring{\hspace{50em}}{: }}% line break in toc
\newcommand*{\dlbtoc}{\texorpdfstring{\hspace{50em}\textcolor{white}{--}\hspace{50em}}{ -- }}% double line break in toc

\begin{document}

\tableofcontents

\part[%
    nonumber=true,%
    tocentry={\bookonetoc\lbtoc\bookonetopictoc\dlbtoc\partonetoc\lbtoc\partonetopictoc}%
]%
{\huge\muc{Erstes Buch}\dlb\muc{Ello, me Dearios}\tlb\LARGE\muc{Erter Teil}\dlb\muc{Ello, me Dearios}}

\end{document}

(\hspace{50em} ist natürlich ein Hack. Wenn ich stattdessen \\ verwende, ist der Abstand zwischen den Zeilen nicht einheitlich. Wenn es dazu vielleicht auch gleich noch einen Tipp gibt, wie sich der Hack evtl. vermeiden lässt, wäre das natürlich super.)


MoeWe
Forum-Meister
Forum-Meister
Beiträge: 801
Registriert: Fr 30. Aug 2019, 15:35
Kontaktdaten:

Re: Parser für Smallcaps

Beitrag von MoeWe »

Sorry, Dein Beispiel ist leider etwas zu kompliziert für mich.

Das folgende Beispiel zeigt, wie Du mit \texorpdfstring ALL-CAPS in den Bookmarks bekommen kannst.

\documentclass[ngerman]{book}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{expl3,xparse}
\usepackage{relsize}
\usepackage{hyperref}

\ExplSyntaxOn
\tl_new:N \l_keth_text_tl

\cs_generate_variant:Nn \text_uppercase:n {o}

\NewDocumentCommand{\textfakesc}{m}
  {
    \tl_set:Nn \l_keth_text_tl {#1}
    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl
    \text_uppercase:o \l_keth_text_tl
  }

\NewExpandableDocumentCommand{\textfakescwithpdfstring}{m}
  {
    \texorpdfstring
      {
        \textfakesc { #1 }
      }
      {
        \text_uppercase:n { #1 }
      }
  }
\ExplSyntaxOff



\begin{document}
\tableofcontents
\part{\textfakescwithpdfstring{Lorem Ipsum Dolor Sit Amet}}
\end{document}

Der \part-Title wird in so großer Schrift gesetzt, dass \larger keine Wirkung mehr hat. Daher ist der Effekt nicht mehr sichtbar.

Idealerweise würde man das \textfakescwithpdfstring direkt in \part einbauen, aber da bin ich überfragt.


keth-tex

Re: Parser für Smallcaps

Beitrag von keth-tex »

Perfekt. Vielen Dank.

Allerdings ist mir gerade noch ein anderes (für Dich vermutlich kleines) Problem aufgefallen:
Umlaute als Großbuchstaben funktionieren einwandfrei. Bei kleinen Umlauten jedoch, fliegt mir das Ding um die Ohren...

Und dann wollte ich nochmal nachfragen wegen des Copy-Paste. Was Du da meintest. - Oder war das nur ein Irrtum?

Wenn man das Ding mit normalen Mitteln in \part einbaut, kommt es tatsächlich zu schwerwiegenden Fehlfunktionen. Ist aber für meine Zwecke, soweit ich sehe, auch nicht notwendig, da ich ohnehin einen eigenen Befehl als Ersatz für \part definieren muss.


MoeWe
Forum-Meister
Forum-Meister
Beiträge: 801
Registriert: Fr 30. Aug 2019, 15:35
Kontaktdaten:

Re: Parser für Smallcaps

Beitrag von MoeWe »

Das liegt wohl an den Umlauten in

    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl

ein paar Tests legen nahe, dass es mit pdfLaTeX nicht wirklich möglich ist, mit l3regex nicht-ASCII-Zeichen zu verarbeiten. Mit den Unicode-Engines LuaLaTeX und XeLaTeX gehts einwandfrei.


keth-tex

Re: Parser für Smallcaps

Beitrag von keth-tex »

Hmm.. Also, ich hatte mal ein wenig herumprobiert.. - Mit

\NewDocumentCommand{\textfakesc}{m}
  {
    \tl_set:Nn \l_keth_text_tl {#1}
    \regex_replace_all:nnN { ([A-ZÄÖÜ]+) } { \cB\{\c{larger}\[1\] \1 \cE\} } \l_keth_text_tl
    \regex_replace_all:nnN { [ä] } { \c{"}A } \l_keth_text_tl
    \regex_replace_all:nnN { [ö] } { \c{"}O } \l_keth_text_tl
    \regex_replace_all:nnN { [ü] } { \c{"}U } \l_keth_text_tl
    \text_uppercase:o \l_keth_text_tl
  }

funktioniert es fast..
Das einzige Problem ist, dass der entsprechende Buchstabe dann doppelt gesetzt wird. (Einmal vergrößert und einmal in der korrekten Größe.) Aber das muss doch noch weg zu bekommen sein...


keth-tex

Re: Parser für Smallcaps

Beitrag von keth-tex »

Wenn ich es richtig sehe, kann der \text_uppercase-Befehl die kleinen Umlaute nicht verarbeiten. Wenn sie zuvor mit Großbuchstaben ersetzt werden könnten, würde es wohl funktionieren.


Antworten