Antag, at jeg gerne vil censurere et forbandelsesord <word>
ved hjælp af grawlixes , f.eks “Hvad # @ $! Laver du ?!” Hvordan kan jeg definere en kommando \censor
, således at \censor{<word>}
resulterer i en streng af disse symboler? Jeg er ikke helt sikker på, hvilke eller hvor mange symboler der skal bruges i betragtning af ordet <word>
. Jeg antager, at antallet af anvendte symboler tilnærmelsesvis skal være lig med antallet af tegn i <word>
.
Tak for dit input!
Kommentarer
- Det er meget lettere at gøre det i teksteditorkilden end i TeX. (luatex er sandsynligvis lettere end klassisk tex, hvis du virkelig vil gøre det på tekstniveau) (Det er let nok at gøre det i begrænsede tekstkontekster, men svært, hvis du har brug for det i vilkårlige afsnit og lister osv.)
- se også tex.stackexchange.com/questions/88394/…
- @percusse I # @ $! &%? !% $ @!% $.
- @GonzaloMedina Kan jeg købe en vokal?
- Nå, i det mindste Jeg lærte et nyt ord i dag. Men hvorfor er ‘ ikke flertallet grawlices ?
Svar
Et tilfældigt symbol tages fra en liste og føjes til en tokenliste; når bredden på de akkumulerede symboler er mere end bredden på ordet minus 2pt, udskrives symbolerne, ellers tilføjes et andet symbol.
\documentclass{article} \usepackage{xparse,pgf} \ExplSyntaxOn \NewDocumentCommand{\censor}{m} { \pointer_censor:n { #1 } } \seq_new:N \g_pointer_grawlixes_seq \tl_map_inline:nn { @ * \# ! \$ \% ? ! \# @ \% *} { \seq_gput_right:Nn \g_pointer_grawlixes_seq { #1 } } \int_const:Nn \c_pointer_grawlix_list_int { \seq_count:N \g_pointer_grawlixes_seq } \dim_new:N \l_pointer_censor_dim \dim_new:N \l_pointer_try_dim \box_new:N \l_pointer_censor_box \tl_new:N \l_pointer_grawlixes_tl \cs_new_protected:Npn \pointer_censor:n #1 { \tl_clear:N \l_pointer_grawlixes_tl \hbox_set:Nn \l_pointer_censor_box { #1 } \dim_set:Nn \l_pointer_censor_dim { \box_wd:N \l_pointer_censor_box } \pointer_add_grawlix: } \cs_new_protected:Npn \pointer_add_grawlix: { \hbox_set:Nn \l_pointer_censor_box { \l_pointer_grawlixes_tl } \dim_compare:nTF { \l_pointer_censor_dim - 2pt < \box_wd:N \l_pointer_censor_box } { \tl_use:N \l_pointer_grawlixes_tl } { \pgfmathparse{random(1,\int_eval:n {\c_pointer_grawlix_list_int})} \tl_put_right:Nx \l_pointer_grawlixes_tl { \seq_item:Nn \g_pointer_grawlixes_seq { \pgfmathresult } } \pointer_add_grawlix: } } \ExplSyntaxOff \begin{document} Censored \censor{Censored} \end{document}
Svar
Et ydmygt forsøg med lualatex
:
Erstatningskoden er meget naiv, vi har brug for noget mere robust.
\documentclass{article} \directlua{ % my list of bad words bad_words = { "fish", "cat", "dog", "horse", "alligator" } % the replacement string replacement = "duck" % a replacement function which returns % both the altered line and the number % of occurrences function replace(line) for _, element in pairs(bad_words) do if string.find(line, element) then return string.gsub(line, element, replacement) end end return line, 0 end % my "naive" censor function, it simply % replaces any occurrences of the % list of bad words by the replacement % string function censor(line) occurrences = 0 repeat line, occurrences = replace(line) until occurrences == 0 return line end % add the hook callback.register("process_input_buffer", censor)} \begin{document} Once upon a time, there was a little cat who lived inside an igloo. Don"t ask me what he was doing there. One day, the cat was visited by his two other friends, the dog and the alligator! --- ``What are you guys doing here?"", said the cat. --- ``We came to visit you, mr.\ cat!"", said the dog. --- ``Our friend horse will be late, he went to the store to buy some frozen fish for you``, replied the alligator. \end{document}
Output:
Moral af historien: Jeg er forfærdelig til at fortælle historier. :)
Lad os nu tilføje grawlixerne . Da jeg har brug for en bedre Lua-kode, lad os oprette en ekstern fil censor.lua
og kalde den fra .tex
kode:
\begin{filecontents*}{censor.lua} -- a list of symbols to represent the -- grawlixe symbols -- note that we need to escape -- some chars grawlixe_symbols = { "\\$", "\\#", "@", "!", "*", "\\&" } -- generate a grawlixe of length s -- note that the seed is not so random, so -- same values of s might get the same -- grawlixe pattern (I could add another seed -- mid code, but I"m lazy) function grawlixe(s) math.randomseed(os.time()) local u = table.getn(grawlixe_symbols) local i = math.random(u) local r = grawlixe_symbols[i] local current local w = 1 repeat current = math.random(u) while current == i do current = math.random(u) end i = current r = r .. grawlixe_symbols[i] w = w + 1 until w == s return r end -- a list of bad words to be censored bad_words = { "fish", "cat", "dog", "horse", "alligator" } -- our replacement function, it returns -- the new line and the number of -- replacements made -- note that this is a very naive replacement -- function, there"s a lot of room for -- improvement function replace(line) for _, element in pairs(bad_words) do if string.find(line, element) then return string.gsub(line, element, grawlixe(string.len(element))) end end return line, 0 end -- the censor function, it repeats -- ad nauseam until the line has -- nothing more to be censored function censor(line) local occurrences = 0 repeat line, occurrences = replace(line) until occurrences == 0 return line end -- register the callback callback.register("process_input_buffer", censor) \end{filecontents*} \documentclass{article} \directlua{dofile("censor.lua")} \begin{document} Once upon a time, there was a little cat who lived inside an igloo. Don"t ask me what he was doing there. One day, the cat was visited by his two other friends, the dog and the alligator! --- ``What are you guys doing here?"", said the cat. --- ``We came to visit you, mr.\ cat!"", said the dog. --- ``Our friend horse will be late, he went to the store to buy some frozen fish for you``, replied the alligator. \end{document}
Outputtet:
Moral i den nye historie: tilføjelse af grawlixes til en tekst får det til at se uartigt ud. :)
Kommentarer
- +1 (selvom jeg håbede på at se et ænderbillede, måske blev det censureret?)
Svar
Hvis man undlader fordele og ulemper ved, hvordan og hvorfor man gør dette, finder jeg det en dejlig lille øvelse at gøre med xstring
. Så her er min mening om det:
\documentclass{article} \usepackage{xstring} \def\grawlix{{\makeatletter@\makeatother}\textdollar{$\sharp$}*?!} \newcommand{\censor}[1]{\StrLen{#1}[\result]% \expandarg\StrLeft{\grawlix}{\result}[]} \begin{document} What the \censor{word} is this??? \end{document}
Som du kan se, er begrænsningen, at grawlix vil være sammensat af det samme sæt tegn i samme rækkefølge. (Du kan omdefinere tegnsættet eller finde en måde at randomisere dem ved hver påkaldelse af makroen … men det “en anden historie! ;)
) Men din grawlix vil være så lang som det censurerede ord.
Hvad der sker er, at xstring
har sine egne måder at udvide argumenter på, og makroerne kan ikke nestes. Så resultatet fra makroen, der finder længden af det censurerede ord returneres i en anden makro (fantasifuldt kaldet her \result
), der (gen) bruges til at opdele den foruddefinerede \grawlix
på det rette sted.
\expandarg
makroen sørger for, at udvidelsen udføres korrekt. Ifølge xstring
dokumentation, vil det tillade, at alle argumenter, der er sendt, udvides nøjagtigt en gang. Derfor skal man være opmærksom på at beskytte grupper, der repræsenterer et enkelt tegn med seler (f.eks. \sharp
symbol lever i mathmode, men vi vil ikke t dollartegnene, der afgrænser det, skal ses som separate tokens).
Kommentarer
- Jeg don ‘ t synes
\makeatletter
og\makeatother
er nødvendige omkring @ … Det kan bruges som det symbol, det er med det samme. - @cgnieder Det ‘ et godt stykke arbejde, de er ikke nødvendige, da de slet ikke har nogen effekt, hvis de bruges inde definitionen som her: – )
- @DavidCarlisle sandt, jeg havde ikke ‘ ikke tænkt på det … Jeg har brug for mere kaffe
Svar
En almindelig TeX-løsning uden yderligere pakker, baseret på ideer fra Kees van der Laan.
\documentclass{article} \begin{document} \newcount\cur \newcount\cura \def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi} \def\mynum#1{\cur\the\lccode`#1\relax\the\cur } \def\process#1{\cur\the\lccode`#1\relax\cura\cur \divide\cura by7 \multiply\cura by7 \advance\cur by-\cura\ifcase\cur!\or@\or\#\or\$\or\%\or\&\or*\else ERROR\fi } \fifo censored \ofif \bigskip \def\censor#1{\fifo #1\ofif} \censor{fuck} \censor{WORD} it is \censor{shit} \end{document}
Du vil sandsynligvis have resultatet forbundet med det anvendte ord.I denne løsning er det \lccode
af et tegnmodul 7. Du kan skrive enten
\fifo censored \ofif
eller som foreslået (undskyld for mit sprog),
\censor{fuck} \censor{WORD} it is \censor{shit}
opnår
Nogle forklaringer. Hovedværktøjet er implantering af FIFO (First-In-First-Out) kø foreslået af Kees van der Laan:
\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi}
\fifo
-kommandoen kalder en makro \process
, der håndterer de enkelte argumenter. Hvert token behandles indtil \ofif
.
Resten er enkel. Manipulering på tællerne \cur
og \cura
får vi et tal mellem 0 og 6 og \ifcase
tager forskellige censurtegn for forskellige værdier.
Bemærk. Jeg er meget interesseret i de virkelige regler ( hvis de findes) for at erstatte forbandelsesord med strenge med @ -lignende symboler.
Kommentarer
- Meget flot. Kan du måske udvide (undskyld ordspillet) lidt om, hvordan koden faktisk fungerer?
- @AlanMunn Ja, men efter hjemkomsten (sent på aftenen).
-
\censor{MSWORD}
Svar
En stabil måde at udveksle symboler på er at ændre fontkodning eller for at genkode skrifttypen. Et simpelt eksempel
\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document}
Med lualatex vil det i fremtiden (når grænsefladen er mere stabil) sandsynligvis være muligt at oprette virtuelle genkodede skrifttyper på-the- flyve, i øjeblikket skal det allerede være muligt at gøre det med en funktionsfil.
Svar
Dette er en udvidelse til @egreg “s svar ved hjælp af et andet svar af @egreg.
Med denne kode kan du indtaste en hel sætning i \censor
og alle ord, der oprindeligt blev føjet til en liste ved hjælp af \addcensor
erstattes af grawlixes. Argumentet for \addcensor
kan enten være et enkelt ord eller en kommasepareret liste.
\documentclass{article} \usepackage{xparse,pgf} \ExplSyntaxOn \NewDocumentCommand{\censor}{m} { \pointer_badseq:n { #1 } } \tl_new:N \g_pointer_badwords_tl \NewDocumentCommand{\addcensor}{m} { \clist_map_inline:nn { #1 } { \tl_gput_right:Nn \g_pointer_badwords_tl { {##1}{} } } } \cs_generate_variant:Nn \str_case:nnTF { nV } \cs_new_protected:Npn \pointer_badseq:n #1 { \seq_set_split:Nnn \l_tmpa_seq { ~ } { #1 } \seq_map_inline:Nn \l_tmpa_seq { \str_case:nVTF { ##1 } \g_pointer_badwords_tl { \pointer_censor:n { ##1 } } { ##1 } ~ % Readd space } \tex_unskip:D % Remove the trailing space } % From @egreg"s answer \seq_new:N \g_pointer_grawlixes_seq \tl_map_inline:nn { @ * \# ! \$ \% ? ! \# @ \% *} { \seq_gput_right:Nn \g_pointer_grawlixes_seq { #1 } } \int_const:Nn \c_pointer_grawlix_list_int { \seq_count:N \g_pointer_grawlixes_seq } \dim_new:N \l_pointer_censor_dim \dim_new:N \l_pointer_try_dim \box_new:N \l_pointer_censor_box \tl_new:N \l_pointer_grawlixes_tl \cs_new_protected:Npn \pointer_censor:n #1 { \tl_clear:N \l_pointer_grawlixes_tl \hbox_set:Nn \l_pointer_censor_box { #1 } \dim_set:Nn \l_pointer_censor_dim { \box_wd:N \l_pointer_censor_box } \pointer_add_grawlix: } \cs_new_protected:Npn \pointer_add_grawlix: { \hbox_set:Nn \l_pointer_censor_box { \l_pointer_grawlixes_tl } \dim_compare:nTF { \l_pointer_censor_dim - 2pt < \box_wd:N \l_pointer_censor_box } { \tl_use:N \l_pointer_grawlixes_tl } { \pgfmathparse{random(1,\int_eval:n {\c_pointer_grawlix_list_int})} \tl_put_right:Nx \l_pointer_grawlixes_tl { \seq_item:Nn \g_pointer_grawlixes_seq { \pgfmathresult } } \pointer_add_grawlix: } } \ExplSyntaxOff \addcensor{censored,duck} \addcensor{street} \begin{document} A censored man walk down the street together with his duck. \censor{A censored man walk down the street together with his duck}. \end{document}
Kommentarer
- Det irriterer mig, når du bruger traditionel placering af åben og lukkebøjle (åben bøjle ved siden af funktionen, så ny linje, derefter koden og derefter lukkebøjlen alene i en ny linje – uden indrykning)), bland den med den anbefalede LaTeX3-måde (begge alene på en ny linje, indrykket samme mængde plads).
- @Manuel Undskyld, Jeg håber, at mit opdaterede svar passer til den anbefalede stil.
- Helt bedre (IMO). Jeg kan godt lide denne måde, selv nu da jeg ‘ læser ConTeXt-kildekode, og den skriver en helt anden (i det mindste bruger de ‘ åbningsbøjlen, ny linje, kode, ny linjelukning uden indrykning for meget, men noget mere som
%
, ny linje, åbningsbøjle og kode, mere kode og lukningsbøjle næste til koden).