% phonenumbers package: phonenumbers.sty % LaTeX package for formatting telephone numbers % Author: K. Wehr % Version: 2.5 % Date: 2022-07-01 % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. \NeedsTeXFormat{LaTeX2e}[2021-11-15] \ProvidesExplPackage {phonenumbers} {2022-07-01} {2.5} {Telephone number package} \RequirePackage {l3keys2e} \clist_const:Nn \c_phone_ziffern_clist {0,1,2,3,4,5,6,7,8,9} \clist_const:Nn \c_phone_gliederungszeichen_clist {(,),[,],/} \clist_const:Nn \c_phone_landeskennzahlen_clist {1, 20, 211, 212, 213, 216, 218, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 27, 290, 291, 297, 298, 299, 30, 31, 32, 33, 34, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 36, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 385, 386, 387, 388, 389, 39, 40, 41, 420, 421, 423, 43, 44, 45, 46, 47, 48, 49, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 51, 52, 53, 54, 55, 56, 57, 58, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 60, 61, 62, 63, 64, 65, 66, 670, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 685, 686, 687, 688, 689, 690, 691, 692, 7, 800, 808, 81, 82, 84, 850, 852, 853, 855, 856, 86, 870, 878, 880, 881, 882, 883, 886, 888, 90, 91, 92, 93, 94, 95, 960, 961, 962, 963, 964, 965, 966, 967, 968, 971, 972, 973, 974, 975, 976, 977, 979, 98, 991, 992, 993, 994, 995, 996, 998} \tl_const:Nn \c_phone_bindestrich_tl { \kern 1pt - \kern 1pt } \tl_const:Nn \c_phone_schraegstrich_tl { \kern 1pt \slash \kern 1pt } \tl_const:Nn \c_phone_pluszeichen_tl { + \kern 1pt } \str_new:N \l_phone_land_str \str_new:N \l_phone_heimatland_str \str_new:N \l_phone_auslandsvorwahltyp_str \str_new:N \l_phone_vorwahl_str \str_new:N \l_phone_vorwahldarstellung_str \str_new:N \l_phone_vorwahltrennung_str \str_new:N \l_phone_auslandsvorwahltrennung_str \str_new:N \l_phone_heimatvorwahl_str \str_new:N \l_phone_bereinigte_nummer_str \str_new:N \l_phone_bereinigte_durchwahl_str \str_new:N \l_phone_linktext_str \int_new:N \l_phone_ziffernzahl_int \int_new:N \l_phone_nummernlaenge_int \int_new:N \l_phone_gruppierungsminimum_int \int_new:N \l_phone_hauptnummernlaenge_int % Nummernlänge im nationalen Format ohne Durchwahl \int_new:N \l_phone_vorwahllaenge_int \int_new:N \l_phone_bindestrichposition_int \tl_new:N \l_phone_ausgabetext_tl \tl_new:N \l_phone_formatierte_nummer_tl \bool_new:N \l_phone_vorwahl_gefunden_bool \bool_new:N \l_phone_zeilenumbruch_bool \bool_new:N \l_phone_eingabe_leer_bool \bool_new:N \l_phone_durchwahl_leer_bool \bool_new:N \l_phone_nummer_verlinken_bool \bool_new:N \l_phone_teilnehmerrufnummer_gueltig_bool \bool_new:N \l_phone_erstes_zeichen_bool \bool_new:N \l_phone_zweites_zeichen_bool \bool_new:N \l_phone_auslandsnummer_bool \bool_new:N \l_phone_null_am_anfang_bool \cs_generate_variant:Nn \str_if_eq:nnT {xnT} \cs_generate_variant:Nn \str_if_eq:nnF {xnF} \cs_generate_variant:Nn \str_if_eq:nnTF {xnTF} \cs_generate_variant:Nn \str_case:nn {xn} \cs_generate_variant:Nn \str_case:nnT {xnT} \cs_generate_variant:Nn \str_case:nnF {xnF} \cs_generate_variant:Nn \str_case:nnTF {xnTF} \cs_generate_variant:Nn \str_tail:n {x} \cs_generate_variant:Nn \tl_put_right:Nn {Nv} \cs_generate_variant:Nn \msg_warning:nnn {onn} \cs_generate_variant:Nn \msg_warning:nnn {nnV} \msg_new:nnn {phonenumbers} {illegal character} { illegal~character~'#1'~in~phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {empty input} { empty~phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {empty extension} { empty~extension~(Durchwahl)~ \msg_line_context: } \msg_new:nnn {phonenumbers} {illegal extension} { extension~(Durchwahl)~of~ \str_if_empty:NTF \l_phone_land_str { unsupported } { \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } } \c_space_tl phone~number~ignored~ \msg_line_context: } \msg_new:nnn {phonenumbers} {odd extension} { \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl non-geographic~number~should~not~contain~an~extension~(Durchwahl)~ \msg_line_context: } \msg_new:nnn {phonenumbers} {subscriber number too short} { subscriber~number~(Teilnehmerrufnummer)~has~less~than~#1~digits~in~ \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {subscriber number too long} { subscriber~number~(Teilnehmerrufnummer)~has~more~than~#1~digits~in~ \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {illegal start of subscriber number} { subscriber~number~(Teilnehmerrufnummer)~starts~with~#1~in~ \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {missing subscriber number} { no~subscriber~number~(Teilnehmerrufnummer)~given~in~ \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {invalid area code} { unknown~area~code~(Vorwahl)~in~ \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl phone~number~ \msg_line_context: } \msg_new:nnn {phonenumbers} {number too short} { \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl #1~number~has~less~than~#2~digits~ \msg_line_context: } \msg_new:nnn {phonenumbers} {number too long} { \use:c { c_phone_ \l_phone_land_str _landesadjektiv_tl } \c_space_tl #1~number~has~more~than~#2~digits~ \msg_line_context: } \msg_new:nnn {phonenumbers} {home country set} { home~country~set~to~ \l_phone_heimatland_str \c_space_tl \msg_line_context: } \msg_new:nnn {phonenumbers} {home country cleared} { home~country~ \l_phone_heimatland_str \c_space_tl has~been~deleted~ \msg_line_context: } \msg_new:nnn {phonenumbers} {home area code set} { Your~home~is~in~ \tl_use:c { c_phone_ \l_phone_heimatland_str _ortsname_ #1 _tl } \c_space_tl (area~code~#1)~according~to~line~ \msg_line_number:. } \msg_new:nnn {phonenumbers} {home area code cleared} { home~area~code~ \l_phone_heimatvorwahl_str \c_space_tl has~been~deleted~\msg_line_context: } \msg_new:nnn {phonenumbers} {invalid home area code} { #1~unknown~as~ \use:c { c_phone_ \l_phone_heimatland_str _landesadjektiv_tl } \c_space_tl geographic~area~code~(Ortsvorwahl)~ \msg_line_context: } \msg_new:nnn {phonenumbers} {invalid country code} { illegal~country~code~ \msg_line_context: } \msg_new:nnn {phonenumbers} {country code only} { phone~number~consists~of~a~country~code~only~ \msg_line_context: } \keys_define:nn {phonenumbers} { country .choices:nn = {DE,AT,FR,UK,US} { \str_set_eq:NN \l_phone_land_str \l_keys_choice_tl }, country .initial:n = DE, country .value_required:n = true } \keys_define:nn {phonenumbers} { home-country .choices:nn = {DE,AT,FR,UK,US,none} { \str_if_eq:VnTF \l_keys_choice_tl {none} { \str_if_empty:NF \l_phone_heimatland_str { \msg_info:nn {phonenumbers} {home country cleared} \str_clear:N \l_phone_heimatland_str } } { \str_set_eq:NN \l_phone_heimatland_str \l_keys_choice_tl \msg_info:nn {phonenumbers} {home country set} } \str_if_empty:NF \l_phone_heimatvorwahl_str { \msg_info:nn {phonenumbers} {home area code cleared} \str_clear:N \l_phone_heimatvorwahl_str } }, home-country .initial:n = none, home-country .value_required:n = true } \keys_define:nn {phonenumbers} { foreign .choices:nn = {off,european,american,international} { \str_set_eq:NN \l_phone_auslandsvorwahltyp_str \l_keys_choice_tl }, foreign .initial:n = off, foreign .default:n = international } \keys_define:nn {phonenumbers} { area-code .choices:nn = {number,place,place-and-number} { \str_set_eq:NN \l_phone_vorwahldarstellung_str \l_keys_choice_tl }, area-code .initial:n = number, area-code .value_required:n = true } \keys_define:nn {phonenumbers} { area-code-sep .choices:nn = {space,slash,brackets,hyphen} { \str_set_eq:NN \l_phone_vorwahltrennung_str \l_keys_choice_tl }, area-code-sep .initial:n = slash, area-code-sep .value_required:n = true } \keys_define:nn {phonenumbers} { foreign-area-code-sep .choices:nn = {space,brackets} { \str_set_eq:NN \l_phone_auslandsvorwahltrennung_str \l_keys_choice_tl }, foreign-area-code-sep .initial:n = space, foreign-area-code-sep .value_required:n = true } \keys_define:nn {phonenumbers} { link .choices:nn = {on,off} { \str_if_eq:VnTF \l_keys_choice_tl {on} { \bool_set_true:N \l_phone_nummer_verlinken_bool } { \bool_set_false:N \l_phone_nummer_verlinken_bool } }, link .initial:n = on, link .value_required:n = true } \keys_define:nn {phonenumbers} { home-area-code .code:n = { \str_if_eq:nnTF {#1} {none} { \str_if_empty:NF \l_phone_heimatvorwahl_str { \msg_info:nn {phonenumbers} {home area code cleared} \str_clear:N \l_phone_heimatvorwahl_str } } { \str_if_empty:NT \l_phone_heimatland_str { \str_set_eq:NN \l_phone_heimatland_str \l_phone_land_str \msg_info:nn {phonenumbers} {home country set} } \use:c { phone_ \l_phone_heimatland_str _heimatvorwahl_erlaubt:nT } {#1} { % Auslassen der Vorwahl möglich, Heimatvorwahl setzen: \str_set:Nn \l_phone_heimatvorwahl_str {#1} \msg_info:nnn {phonenumbers} {home area code set} {#1} } } }, home-area-code .initial:n = none, home-area-code .value_required:n = true } \keys_define:nn {phonenumbers} { group-min .choices:nn = {3,4,5,6,7} { \int_set_eq:NN \l_phone_gruppierungsminimum_int \l_keys_choice_tl }, group-min .initial:n = {3} , group-min .value_required:n = true } % einen Nummernteil von vorne in Zweiergruppen gruppiert schreiben, sofern er nicht kürzer als das Gruppierungsminimum ist \cs_new_protected:Npn \phone_von_vorne_gruppiert_schreiben:n #1 { \int_set:Nn \l_phone_ziffernzahl_int { \tl_count:n {#1} } \tl_clear:N \l_phone_formatierte_nummer_tl \int_step_inline:nn {\l_phone_ziffernzahl_int} { \tl_put_right:Nx \l_phone_formatierte_nummer_tl { \tl_item:nn {#1} {##1} } % Nach jeder zweiten Ziffer wird ein kleiner Abstand eingefügt, wenn die Ziffernzahl nicht unterhalb des Gruppierungsminimums liegt. \bool_lazy_all:nT { { ! \int_compare_p:nNn { \l_phone_ziffernzahl_int } < { \l_phone_gruppierungsminimum_int } } { \int_if_even_p:n {##1} } { \int_compare_p:nNn {##1} < { \l_phone_ziffernzahl_int } } } { \tl_put_right:Nn \l_phone_formatierte_nummer_tl {\,} } } \tl_put_right:NV \l_phone_ausgabetext_tl \l_phone_formatierte_nummer_tl } \cs_generate_variant:Nn \phone_von_vorne_gruppiert_schreiben:n {x,V} % einen Nummernteil in Zweiergruppen gruppiert mit führender Einzelziffer schreiben, sofern er nicht kürzer als das Gruppierungsminimum ist \cs_new_protected:Npn \phone_versetzt_gruppiert_schreiben:n #1 { \int_set:Nn \l_phone_ziffernzahl_int { \tl_count:n {#1} } \tl_clear:N \l_phone_formatierte_nummer_tl \int_step_inline:nn {\l_phone_ziffernzahl_int} { \tl_put_right:Nx \l_phone_formatierte_nummer_tl { \tl_item:nn {#1} {##1} } % Nach der 1., 3., 5., ... Ziffer wird ein kleiner Abstand eingefügt, wenn die Ziffernzahl nicht unterhalb des Gruppierungsminimums liegt. \bool_lazy_all:nT { { ! \int_compare_p:nNn { \l_phone_ziffernzahl_int } < { \l_phone_gruppierungsminimum_int } } { \int_if_odd_p:n {##1} } { \int_compare_p:nNn {##1} < { \l_phone_ziffernzahl_int } } } { \tl_put_right:Nn \l_phone_formatierte_nummer_tl {\,} } } \tl_put_right:NV \l_phone_ausgabetext_tl \l_phone_formatierte_nummer_tl } \cs_generate_variant:Nn \phone_versetzt_gruppiert_schreiben:n {x} % einen Nummernteil von hinten in Zweiergruppen gruppiert schreiben, sofern er nicht kürzer als das Gruppierungsminimum ist \cs_new_protected:Npn \phone_von_hinten_gruppiert_schreiben:n #1 { \int_set:Nn \l_phone_ziffernzahl_int { \tl_count:n {#1} } \tl_clear:N \l_phone_formatierte_nummer_tl \int_step_inline:nnnn {\l_phone_ziffernzahl_int} {-1} {1} { \tl_put_left:Nx \l_phone_formatierte_nummer_tl { \tl_item:nn {#1} {##1} } % Nach jeder zweiten Ziffer wird ein kleiner Abstand eingefügt, wenn die Ziffernzahl nicht unterhalb des Gruppierungsminimums liegt. \bool_lazy_all:nT { { ! \int_compare_p:nNn { \l_phone_ziffernzahl_int } < { \l_phone_gruppierungsminimum_int } } { \int_if_even_p:n { \l_phone_ziffernzahl_int + 1 - ##1 } } { \int_compare_p:nNn {##1} > {1} } } { \tl_put_left:Nn \l_phone_formatierte_nummer_tl {\,} } } \tl_put_right:NV \l_phone_ausgabetext_tl \l_phone_formatierte_nummer_tl } \cs_generate_variant:Nn \phone_von_hinten_gruppiert_schreiben:n {x,V} % #1: Vorwahl, #2: Soll die führende Null ausgegeben werden? \cs_new_protected:Npn \phone_geklammerte_ziffernvorwahl_schreiben:nN #1#2 { % Klammern werden nur bei Ortsvorwahlen gesetzt \clist_if_in:cnTF { c_phone_ \l_phone_land_str _ortsvorwahlen_clist } {#1} { \tl_put_right:Nn \l_phone_ausgabetext_tl {(} \use:c { phone_ \l_phone_land_str _ziffernvorwahl_schreiben:nN } {#1} #2 \tl_put_right:Nn \l_phone_ausgabetext_tl {)} } { \use:c { phone_ \l_phone_land_str _ziffernvorwahl_schreiben:nN } {#1} #2 } } % #1: Landeskennzahl \cs_new_protected:Npn \phone_gruppierte_auslandsvorwahl_schreiben:n #1 { \str_case:Vn \l_phone_auslandsvorwahltyp_str { {international} { \tl_put_right:Nn \l_phone_ausgabetext_tl { \c_phone_pluszeichen_tl #1 } } {european} { \phone_von_hinten_gruppiert_schreiben:n { 00 #1 } } {american} { \phone_von_hinten_gruppiert_schreiben:n { 011 #1 } } } } \cs_generate_variant:Nn \phone_gruppierte_auslandsvorwahl_schreiben:n {x} % #1: Landeskennzahl \cs_new_protected:Npn \phone_ungruppierte_auslandsvorwahl_schreiben:n #1 { \tl_put_right:Nx \l_phone_ausgabetext_tl { \str_case:VnF \l_phone_auslandsvorwahltyp_str { {european} { 00 #1 } {american} { 011 #1 } } { \c_phone_pluszeichen_tl #1 } } } \cs_generate_variant:Nn \phone_ungruppierte_auslandsvorwahl_schreiben:n {V} % #1: eingebene Nummer \cs_new_protected:Npn \phone_nummer_ueberpruefen:n #1 { \tl_if_blank:nTF {#1} { \msg_warning:nn {phonenumbers} {empty input} \bool_set_true:N \l_phone_eingabe_leer_bool } { \bool_set_false:N \l_phone_eingabe_leer_bool } \str_clear:N \l_phone_bereinigte_nummer_str \bool_set_true:N \l_phone_erstes_zeichen_bool \bool_set_false:N \l_phone_zweites_zeichen_bool \bool_set_false:N \l_phone_auslandsnummer_bool \bool_set_false:N \l_phone_null_am_anfang_bool \tl_map_inline:nn {#1} { \clist_if_in:NnTF \c_phone_ziffern_clist {##1} { % Ziffer eingelesen \str_put_right:Nn \l_phone_bereinigte_nummer_str {##1} \bool_lazy_and:nnT {\l_phone_erstes_zeichen_bool} { \str_if_eq_p:nn {##1} {0} } { \bool_set_true:N \l_phone_null_am_anfang_bool } \bool_if:NT \l_phone_zweites_zeichen_bool { \bool_set_false:N \l_phone_zweites_zeichen_bool \bool_lazy_and:nnT {\l_phone_null_am_anfang_bool} { \str_if_eq_p:nn {##1} {0} } { \bool_set_true:N \l_phone_auslandsnummer_bool \str_clear:N \l_phone_bereinigte_nummer_str } } \bool_if:NT \l_phone_erstes_zeichen_bool { \bool_set_false:N \l_phone_erstes_zeichen_bool \bool_set_true:N \l_phone_zweites_zeichen_bool } } { % keine Ziffer eingelesen \bool_lazy_and:nnTF {\l_phone_erstes_zeichen_bool} { \str_if_eq_p:nn {##1} {+} } { % führendes + eingelesen \bool_set_true:N \l_phone_auslandsnummer_bool \bool_set_false:N \l_phone_erstes_zeichen_bool } { \clist_if_in:NnF \c_phone_gliederungszeichen_clist {##1} { \str_if_eq:nnTF {##1} {-} { % Bindestrich eingelesen \str_put_right:Nn \l_phone_bereinigte_nummer_str {-} } { % unerlaubtes Zeichen (z. B. Buchstaben) eingelesen \msg_warning:nnx {phonenumbers} {illegal character} {##1} } } } } } \bool_if:NT \l_phone_auslandsnummer_bool { \int_set:Nn \l_tmpa_int { \str_count:N \l_phone_bereinigte_nummer_str } \int_compare:nNnTF {\l_tmpa_int} > {1} { \str_if_eq:xnTF { \str_head:N \l_phone_bereinigte_nummer_str } {1} { \str_set:Nn \l_phone_land_str {US} \str_set:Nx \l_phone_bereinigte_nummer_str { \str_tail:N \l_phone_bereinigte_nummer_str } } { \int_compare:nNnTF {\l_tmpa_int} > {2} { \str_case:xnTF { \str_range:Nnn \l_phone_bereinigte_nummer_str {1} {2} } { {33} { \str_set:Nn \l_phone_land_str {FR} } {43} { \str_set:Nn \l_phone_land_str {AT} } {44} { \str_set:Nn \l_phone_land_str {UK} } {49} { \str_set:Nn \l_phone_land_str {DE} } } { \str_set:Nx \l_phone_bereinigte_nummer_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {3} {-1} } \str_put_left:Nn \l_phone_bereinigte_nummer_str {0} } { \int_compare:nNnTF {\l_tmpa_int} > {3} { \str_case:xnTF { \str_range:Nnn \l_phone_bereinigte_nummer_str {1} {3} } { {262} { \str_set:Nx \l_phone_bereinigte_nummer_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {4} {-1} } } {508} { } % Saint-Pierre-et-Miquelon {590} { \str_set:Nx \l_phone_bereinigte_nummer_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {4} {-1} } } {594} { \str_set:Nx \l_phone_bereinigte_nummer_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {4} {-1} } } {596} { \str_set:Nx \l_phone_bereinigte_nummer_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {4} {-1} } } } { \str_set:Nn \l_phone_land_str {FR} \str_put_left:Nn \l_phone_bereinigte_nummer_str {0} } { \str_clear:N \l_phone_land_str % Länge größer 3, nicht mit 262, 508, 590, 594 oder 596 beginnend } } { \str_clear:N \l_phone_land_str % Länge 3, nicht mit 33, 43, 44 oder 49 beginnend } } } { \str_clear:N \l_phone_land_str % Länge 2, nicht mit 1 beginnend } } } { \str_clear:N \l_phone_land_str % Länge kleiner oder gleich 1 } } \bool_lazy_all:nT { { ! \str_if_empty_p:N \l_phone_land_str } { \bool_if_p:c { c_phone_ \l_phone_land_str _erlaubt_durchwahl_bool } } { \str_if_empty_p:N \l_phone_bereinigte_durchwahl_str } } { % Nummer ohne explizite Durchwahl in einem Land, das Durchwahlen erlaubt \int_set:Nn \l_phone_bindestrichposition_int {-1} \int_step_inline:nnnn { \str_count:N \l_phone_bereinigte_nummer_str } {-1} {1} { \int_compare:nNnT {\l_phone_bindestrichposition_int} = {-1} { \str_if_eq:xnT { \str_item:Nn \l_phone_bereinigte_nummer_str {##1} } {-} { \int_set:Nn \l_phone_bindestrichposition_int {##1} } } } \int_compare:nNnF {\l_phone_bindestrichposition_int} = {-1} { % Nummer enthält einen Bindestrich \str_set:Nx \l_tmpa_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {1} { \l_phone_bindestrichposition_int - 1 } } \tl_remove_all:Nn \l_tmpa_str {-} \phone_enthaelt_vorwahl:NT \l_tmpa_str { \int_compare:nNnT { \str_count:N \l_phone_vorwahl_str } < { \str_count:N \l_tmpa_str } { % dem Bindestrich geht eine Vorwahl voran und der Teil vor dem Bindestrich ist länger als die bloße Vorwahl \bool_set_true:N \l_tmpa_bool } } \str_if_eq:xnF { \str_head:N \l_tmpa_str } {0} { \bool_set_true:N \l_tmpa_bool % Nummer beginnt nicht mit 0 (ist also eine reine Teilnehmerrufnummer) } \bool_if:NT \l_tmpa_bool { % Teil nach dem Bindestrich als Durchwahl abtrennen \phone_durchwahl_ueberpruefen:x { \str_range:Nnn \l_phone_bereinigte_nummer_str { \l_phone_bindestrichposition_int + 1 } {-1} } \str_set_eq:NN \l_phone_bereinigte_nummer_str \l_tmpa_str } } } \tl_remove_all:Nn \l_phone_bereinigte_nummer_str {-} } \cs_generate_variant:Nn \phone_nummer_ueberpruefen:n {x} % #1: eingebene Durchwahl \cs_new_protected:Npn \phone_durchwahl_ueberpruefen:n #1 { \tl_if_blank:nTF {#1} { \msg_warning:nn {phonenumbers} {empty extension} \bool_set_true:N \l_phone_durchwahl_leer_bool } { \bool_set_false:N \l_phone_durchwahl_leer_bool } \str_clear:N \l_phone_bereinigte_durchwahl_str \tl_map_inline:nn {#1} { \clist_if_in:NnTF \c_phone_ziffern_clist {##1} { \str_put_right:Nn \l_phone_bereinigte_durchwahl_str {##1} } { \msg_warning:nnx {phonenumbers} {illegal character} {##1} } } } \cs_generate_variant:Nn \phone_durchwahl_ueberpruefen:n {x} \cs_new_protected:Npn \phone_nummer_ausgeben: { \bool_if:NF \l_phone_eingabe_leer_bool { \str_if_empty:NTF \l_phone_land_str { \phone_nicht_unterstuetzte_nummer_schreiben: } { \use:c {phone_ \l_phone_land_str _nummer_schreiben:} } } \bool_lazy_and:nnTF {\l_phone_nummer_verlinken_bool} { ! \str_if_empty_p:N \l_phone_linktext_str } { \IfPackageLoadedTF {hyperref} { \href { tel \c_colon_str \l_phone_linktext_str } {\l_phone_ausgabetext_tl} } { \l_phone_ausgabetext_tl } } { \l_phone_ausgabetext_tl } } \NewDocumentCommand \setphonenumbers {m} { \keys_set:no {phonenumbers} {#1} } \NewDocumentCommand \phonenumber {omo} { \group_begin: \IfValueT {#1} { \keys_set:no {phonenumbers} {#1} } \IfValueT {#3} { \phone_durchwahl_ueberpruefen:x {#3} } \phone_nummer_ueberpruefen:x {#2} \IfValueT {#3} { \bool_lazy_or:nnT { \str_if_empty_p:N \l_phone_land_str } { ! \bool_if_p:c { c_phone_ \l_phone_land_str _erlaubt_durchwahl_bool } } { \bool_if:NF \l_phone_durchwahl_leer_bool { \msg_warning:nn {phonenumbers} {illegal extension} } } } \phone_nummer_ausgeben: \group_end: } \NewDocumentCommand \AreaCodesGeographic {o} { \group_begin: \IfValueT {#1} { \keys_set:no {phonenumbers} {#1} } \use:c { phone_ \l_phone_land_str _vorwahlliste_ausgeben:n } {ortsvorwahlen} \group_end: } \NewDocumentCommand \AreaCodesNonGeographic {o} { \group_begin: \IfValueT {#1} { \keys_set:no {phonenumbers} {#1} } \use:c { phone_ \l_phone_land_str _vorwahlliste_ausgeben:n } {sondervorwahlen} \group_end: } \NewDocumentCommand \CountryCodes { } { \bool_set_false:N \l_phone_zeilenumbruch_bool \clist_map_inline:Nn \c_phone_landeskennzahlen_clist { \bool_if:NTF \l_phone_zeilenumbruch_bool { \\ } { \bool_set_true:N \l_phone_zeilenumbruch_bool } ##1 } } % #1: Nummer, die auf Enthaltensein einer Vorwahl überprüft wird \prg_new_protected_conditional:Npnn \phone_enthaelt_vorwahl:N #1 {TF,T} { \bool_set_false:N \l_phone_vorwahl_gefunden_bool \int_set:Nn \l_phone_nummernlaenge_int { \str_count:N #1 } \int_step_inline:nnnn {6} {-1} {2} { \bool_if:NF \l_phone_vorwahl_gefunden_bool { \int_compare:nT { \l_phone_nummernlaenge_int >= ##1 } { \str_set:Nx \l_phone_vorwahl_str { \str_range:Nnn #1 {1} {##1} } \clist_if_in:cVT { c_phone_ \l_phone_land_str _vorwahlen_clist } \l_phone_vorwahl_str { \bool_set_true:N \l_phone_vorwahl_gefunden_bool } } } } \bool_if:NTF \l_phone_vorwahl_gefunden_bool { \prg_return_true: } { \prg_return_false: } } % #1: Nummer, #2: Mindestlänge, #3: Höchstlänge, #4: Nummernart \cs_new_protected:Npn \phone_nummernlaenge_ueberpruefen:nnnn #1#2#3#4 { \int_set:Nn \l_tmpa_int { \str_count:n {#1} } \int_compare:nNnTF {\l_tmpa_int} < {#2} { \msg_warning:nnnn {phonenumbers} {number too short} {#4} {#2} } { \int_compare:nNnTF {\l_tmpa_int} > {#3} { \msg_warning:nnnn {phonenumbers} {number too long} {#4} {#3} } { \bool_set_true:N \l_phone_teilnehmerrufnummer_gueltig_bool } } } \cs_generate_variant:Nn \phone_nummernlaenge_ueberpruefen:nnnn {V,o} \cs_new_protected:Npn \phone_nicht_unterstuetzte_nummer_schreiben: { \int_set:Nn \l_phone_nummernlaenge_int { \str_count:N \l_phone_bereinigte_nummer_str } \bool_set_false:N \l_phone_vorwahl_gefunden_bool \int_step_inline:nnnn {3} {-1} {1} { \bool_if:NF \l_phone_vorwahl_gefunden_bool { \int_compare:nT { \l_phone_nummernlaenge_int >= ##1 } { \str_set:Nx \l_tmpa_str { \str_range:Nnn \l_phone_bereinigte_nummer_str {1} {##1} } \clist_if_in:NVT \c_phone_landeskennzahlen_clist \l_tmpa_str { \bool_set_true:N \l_phone_vorwahl_gefunden_bool \phone_ungruppierte_auslandsvorwahl_schreiben:V \l_tmpa_str \int_compare:nNnTF {##1} = {\l_phone_nummernlaenge_int} { \msg_warning:nn {phonenumbers} {country code only} } { \tl_put_right:NV \l_phone_ausgabetext_tl \c_space_tl \phone_von_hinten_gruppiert_schreiben:x { \str_range:Nnn \l_phone_bereinigte_nummer_str {##1 + 1} {-1} } \str_put_right:Nn \l_phone_linktext_str {+} \str_put_right:NV \l_phone_linktext_str \l_phone_bereinigte_nummer_str } } } } } \bool_if:NF \l_phone_vorwahl_gefunden_bool { \msg_warning:nnn {phonenumbers} {invalid country code} \tl_put_right:NV \l_phone_ausgabetext_tl \c_phone_pluszeichen_tl \tl_put_right:NV \l_phone_ausgabetext_tl \l_phone_bereinigte_nummer_str } } \file_input:n {phonenumbers-AT.def} \file_input:n {phonenumbers-DE.def} \file_input:n {phonenumbers-FR.def} \file_input:n {phonenumbers-UK.def} \file_input:n {phonenumbers-US.def} \ProcessKeysPackageOptions {phonenumbers}