Ein Befehlsargument, in dem nur bestimmte Zeichen (sagen wir beispielshalber Ich habe eine Umsetzung auf der Grundlage zweier verschiedener expl3-Datenstrukturen (token list und string) versucht, aber beides funktioniert nicht, wie es soll. Bei der String-Variante liegt dies offenbar daran, dass das zweite Argument von Open in Online-Editor
\documentclass{article} \usepackage[check-declarations]{expl3} \usepackage{xparse} \ExplSyntaxOn \int_new:N \l_zeichenzahl_int \tl_new:N \l_zeichen_tl \str_new:N \l_zeichen_str \cs_new_protected:Npn \test_mit_tl:n #1 { \int_set:Nn \l_zeichenzahl_int {\str_count_ignore_spaces:n {#1}} \cs_set:Npn \zeichen_pruefen:n ##1 { \tl_set:Nn \l_zeichen_tl {\str_item_ignore_spaces:nn {#1} {##1}} \tl_case:NnF \l_zeichen_tl { 0 {} 1 {} a {} b {} } {\PackageWarning{noname}{Falsches~Zeichen:~\l_zeichen_tl}} } \int_step_function:nnnN {1} {1} {\l_zeichenzahl_int} \zeichen_pruefen:n } \cs_new_protected:Npn \test_mit_str:n #1 { \int_set:Nn \l_zeichenzahl_int {\str_count_ignore_spaces:n {#1}} \cs_set:Npn \zeichen_pruefen:n ##1 { \str_set:Nn \l_zeichen_str {\str_item_ignore_spaces:nn {#1} {##1}} \str_case:nnF {\l_zeichen_str} { {0} {} {1} {} {a} {} {b} {} } {\PackageWarning{noname}{Falsches~Zeichen:~\l_zeichen_str}} } \int_step_function:nnnN {1} {1} {\l_zeichenzahl_int} \zeichen_pruefen:n } \NewDocumentCommand \Befehl {m} { \test_mit_tl:n {#1} \test_mit_str:n {#1} } \ExplSyntaxOff \begin{document} \Befehl{12ab} \end{document} gefragt 23 Mai '16, 17:41 Cletus |
Du hast in beiden Definitionen kleine aber wesentliche Fehler. In der Tokenlist-Definition hast Du folgende Zeile: Öffne in Overleaf
\tl_set:Nn \l_zeichen_tl {\str_item_ignore_spaces:nn {#1} {##1}} Wenn Du die damit definierte Tokenlist mit Öffne in Overleaf
> \l_zeichen_tl=\str_item_ignore_spaces:nn {12ab}{1} Ändere die Zeile in Öffne in Overleaf
\tl_set:Nx \l_zeichen_tl {\str_item_ignore_spaces:nn {#1} {##1}} und daraus wird Öffne in Overleaf
> \l_zeichen_tl=1 Das reicht aber noch nicht. Öffne in Overleaf
\tl_const:Nn \c_zeichen_case_a_tl {0} \tl_const:Nn \c_zeichen_case_b_tl {1} \tl_const:Nn \c_zeichen_case_c_tl {a} \tl_const:Nn \c_zeichen_case_d_tl {b} und verwenden: Öffne in Overleaf
\tl_case:NnF \l_zeichen_tl { \c_zeichen_case_a_tl {} \c_zeichen_case_b_tl {} \c_zeichen_case_c_tl {} \c_zeichen_case_d_tl {} } {...} Das reicht immer noch nicht: in Tokenlists hängt ein Match auch vom Kategoriecode der Zeichen ab. Mit Öffne in Overleaf
\tl_set:Nx \l_zeichen_tl {\str_item_ignore_spaces:nn {#1} {##1}} ensteht eine Tokenliste, in der alle Zeichen Kategoriecode 12 haben. In den Testvariablen haben sie das mit obiger Definition nicht. Darum ändern wir noch mal: Öffne in Overleaf
\tl_set:Nx \l_zeichen_tl {\tl_item:nn {#1} {##1}} Und jetzt klappt der Test. In der String-Variante hast Du ähnliche Fehler: Öffne in Overleaf
\str_set:Nn \l_zeichen_str {\str_item_ignore_spaces:nn {#1} {##1}} Ändere das in Öffne in Overleaf
\str_set:Nx \l_zeichen_str {\str_item_ignore_spaces:nn {#1} {##1}} Außerdem hast Du Öffne in Overleaf
\str_case:nnF {\l_zeichen_str} ... Das vergleicht aber nicht den Inhalt der Variablen Öffne in Overleaf
\str_case:VnF \l_zeichen_str ... die Du am besten mit Öffne in Overleaf
\cs_generate_variant:Nn \str_case:nnF {V} bereitstellst. Mit diesen Korrekturen funktioniert Dein Code: Öffne in Overleaf
\documentclass{article} \usepackage[check-declarations]{expl3} \usepackage{xparse} \ExplSyntaxOn \int_new:N \l_zeichenzahl_int \tl_new:N \l_zeichen_tl \str_new:N \l_zeichen_str \tl_const:Nn \c_zeichen_case_a_tl {0} \tl_const:Nn \c_zeichen_case_b_tl {1} \tl_const:Nn \c_zeichen_case_c_tl {a} \tl_const:Nn \c_zeichen_case_d_tl {b} \cs_new_protected:Npn \test_mit_tl:n #1 { \int_set:Nn \l_zeichenzahl_int {\str_count_ignore_spaces:n {#1}} \cs_set:Npn \zeichen_pruefen:n ##1 { \tl_set:Nx \l_zeichen_tl {\tl_item:nn {#1} {##1}} \tl_case:NnF \l_zeichen_tl { \c_zeichen_case_a_tl {} \c_zeichen_case_b_tl {} \c_zeichen_case_c_tl {} \c_zeichen_case_d_tl {} } {\PackageWarning{noname}{Falsches~Zeichen~(tl):~\l_zeichen_tl}} } \int_step_function:nnnN {1} {1} {\l_zeichenzahl_int} \zeichen_pruefen:n } \cs_new_protected:Npn \test_mit_str:n #1 { \int_set:Nn \l_zeichenzahl_int {\str_count_ignore_spaces:n {#1}} \cs_set:Npn \zeichen_pruefen:n ##1 { \str_set:Nx \l_zeichen_str {\str_item_ignore_spaces:nn {#1} {##1}} \str_case:VnF {\l_zeichen_str} { {0} {} {1} {} {a} {} {b} {} } {\PackageWarning{noname}{Falsches~Zeichen~(str):~\l_zeichen_str}} } \int_step_function:nnnN {1} {1} {\l_zeichenzahl_int} \zeichen_pruefen:n } \cs_generate_variant:Nn \str_case:nnF {V} \NewDocumentCommand \Befehl {m} { \test_mit_tl:n {#1} \test_mit_str:n {#1} } \ExplSyntaxOff \begin{document} \Befehl{12ab} \Befehl{12 ab} \end{document} Im Log: Öffne in Overleaf
Package noname Warning: Falsches Zeichen (tl): 2 on input line 63. Package noname Warning: Falsches Zeichen (str): 2 on input line 63. Package noname Warning: Falsches Zeichen (tl): 2 on input line 65. Package noname Warning: Falsches Zeichen (str): 2 on input line 65. Das ganze geht aber auch erheblich leichter: Öffne in Overleaf
\documentclass{article} \usepackage{expl3,xparse} \ExplSyntaxOn \tl_new:N \l_check_input_allowed_tl \tl_set:Nn \l_check_input_allowed_tl {01ab} \cs_new_protected:Npn \check_input:n #1 { \tl_map_inline:nn {#1} { \tl_if_in:NnF \l_check_input_allowed_tl {##1} { \PackageWarning {noname} {Falsche~ Zeichen:~ `##1'} } } } \NewDocumentCommand \checkinput {m} { \check_input:n {#1} } \ExplSyntaxOff \begin{document} \checkinput{} \checkinput{foo} \checkinput{ab10} \checkinput{a1b0} \checkinput{a1c0} \checkinput{ab 10} \end{document} Im Log: Öffne in Overleaf
Package noname Warning: Falsche Zeichen: `f' on input line 26. Package noname Warning: Falsche Zeichen: `o' on input line 26. Package noname Warning: Falsche Zeichen: `o' on input line 26. Package noname Warning: Falsche Zeichen: `c' on input line 29. beantwortet 24 Mai '16, 13:20 cgnieder |
Ich würde das mit einer Open in Online-Editor
\documentclass{article} \usepackage{xparse} \ExplSyntaxOn \clist_new:N \l_allowed_chars_clist \clist_set:Nn \l_allowed_chars_clist { 0, 1, a, b } \msg_new:nnn { noname } { erroneous-input } { Erroneous~character~`#1' } \cs_new_protected:Npn \test_mit_tl:n #1 { % Check for spaces \seq_set_split:Nnn \l_tmpa_seq { ~ } { #1 } \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 } { \msg_warning:nnn { noname } { erroneous-input } { ~ } } % Check for invalid tokens \tl_map_inline:nn { #1 } { \clist_if_in:NnF \l_allowed_chars_clist { ##1 } { \msg_warning:nnn { noname } { erroneous-input } { ##1 } } } } \NewDocumentCommand \Befehl {m} { \test_mit_tl:n {#1} } \ExplSyntaxOff \begin{document} \Befehl{12 ab} \end{document} beantwortet 23 Mai '16, 18:54 Henri Der zweite
(23 Mai '16, 22:32)
Cletus
Etwas unschön ist es, dass die Warnung zweimal ausgegeben wird (jeweils mit einem Fragezeichen anstelle des eigentlichen Zeichens), falls das falsche Zeichen ein Umlaut ist. Der Hintergrund ist mir klar: In UTF-8 werden Umlaute anders als gewöhnliche lateinische Buchstaben durch zwei Byte codiert. Aber kann eine moderne, in Unicode-Zeiten entstandene Sprache wie expl3 so etwas nicht angemessener behandeln?
(26 Mai '16, 00:26)
Cletus
|
Sehe ich das richtig, dass Leerzeichen ignoriert werden sollen? Was ist mit komplett leerem Input?
Ja, Leerzeichen stören in diesem Fall nicht und sollen ignoriert werden. Eine leere Eingabe ist dagegen nicht erwünscht/sinnvoll.