Supponi di voler censurare una parolaccia <word>
usando grawlixes , ad es “Che diavolo stai facendo # @ $! ?!” Come posso definire un comando \censor
tale che \censor{<word>}
restituisca una stringa di questi simboli? Non sono del tutto sicuro di quale o quanti simboli debbano essere utilizzati data la parola <word>
. Suppongo che il numero di simboli utilizzati dovrebbe essere approssimativamente uguale al numero di caratteri in <word>
.
Grazie per il tuo contributo!
Commenti
- È molto più facile farlo nel sorgente delleditor di testo che in TeX. (luatex è probabilmente più facile del classico tex se vuoi davvero farlo a livello di testo) (È abbastanza facile farlo in contesti di testo ristretti ma difficile se devi farlo in paragrafi ed elenchi arbitrari ecc.)
- vedi anche tex.stackexchange.com/questions/88394/…
- @percusse I # @ $! &%? !% $ @!% $.
- @GonzaloMedina Posso comprare una vocale?
- Beh, almeno Oggi ho imparato una nuova parola . Ma perché ‘ non è il plurale grawlices ?
Answer
Un simbolo casuale viene preso da un elenco e aggiunto a un elenco di token; quando la larghezza dei simboli accumulati è maggiore della larghezza della parola meno 2pt, i simboli vengono stampati, altrimenti viene aggiunto un altro simbolo.
\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}
Risposta
Un umile tentativo con lualatex
:
Il codice sostitutivo è molto ingenuo, avremmo bisogno di qualcosa di più robusto.
\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}
Loutput:
Morale di la storia: Non sono bravo a raccontare storie. :)
Ora, aggiungiamo i grawlix . Dato che ho bisogno di un codice Lua migliore, creiamo un file esterno censor.lua
e chiamiamolo dal .tex
codice:
\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}
Loutput:
Morale della nuova storia: laggiunta di grawlix a un testo lo fa sembrare cattivo. :)
Commenti
- +1 (anche se speravo di vedere una foto di anatra, forse è stata censurata?)
Risposta
Lasciando da parte i pro e i contro di come e perché farlo, trovo che sia un piccolo esercizio carino da fare con xstring
. Ecco la mia opinione:
\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}
Come puoi vedere, la limitazione è che il grawlix sarà composto dallo stesso set di caratteri, nello stesso ordine. (Puoi ridefinire il set di caratteri o trovare un modo per randomizzarli a ogni invocazione della macro … ma questa “è una storia diversa! ;)
) Ma il tuo grawlix sarà tanto lungo come parola censurata.
Quello che succede è che xstring
ha i suoi modi di espandere gli argomenti e le macro non possono essere nidificate. Quindi il risultato della macro che trova la lunghezza della parola censurata viene restituita in una macro diversa (chiamata qui in modo fantasioso \result
) che verrà (ri) utilizzata per suddividere il \grawlix
nel punto giusto.
La macro \expandarg
si assicura che lespansione sia eseguita correttamente. Secondo xstring
documentazione, consentirà a tutti gli argomenti passati di essere espansi esattamente una volta. Pertanto, è necessario prestare attenzione a proteggere i gruppi che rappresentano un singolo carattere con parentesi graffe (ad esempio \sharp
il simbolo vive in modalità matematica, ma noi non vogliamo t i segni del dollaro che lo delimitano per essere visti come gettoni separati).
Commenti
- I don ‘ Non credo che
\makeatletter
e\makeatother
siano necessari intorno a @ … Può essere usato come simbolo che è subito. - @cgnieder È ‘ un buon lavoro, non sono necessari in quanto non hanno alcun effetto se usati allinterno della definizione come qui: – )
- @DavidCarlisle true, non ci avevo ‘ pensato … ho bisogno di altro caffè
Risposta
Una semplice soluzione TeX senza pacchetti aggiuntivi, basata sulle idee di 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}
Probabilmente vuoi che il risultato sia connesso alla parola usata.In questa soluzione è \lccode
di un carattere modulo 7. Puoi scrivere
\fifo censored \ofif
o, come suggerito (scusa per la mia lingua),
\censor{fuck} \censor{WORD} it is \censor{shit}
ottenendo
Alcune spiegazioni. Lo strumento principale è limplementazione della coda FIFO (First-In-First-Out) suggerita da Kees van der Laan:
\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi}
Il chiama una macro \process
che gestisce i singoli argomenti. Ogni token viene elaborato fino al \ofif
.
Il resto è semplice. Manipolando sui contatori \cur
e \cura
si ottiene un numero compreso tra 0 e 6 e \ifcase
accetta caratteri di censura diversi per valori diversi.
Nota. Sono molto interessato alle regole reali ( se esistono) di sostituire parolacce con stringhe di simboli simili a @.
Commenti
- Molto carino. Potresti forse espandere (scusa il gioco di parole) un po su come funziona effettivamente il codice?
- @AlanMunn Sì, ma dopo essere tornato a casa (a tarda sera).
-
\censor{MSWORD}
Risposta
Un modo stabile per scambiare simboli è cambiare la codifica dei caratteri o per ricodificare il carattere. Un semplice esempio
\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document}
Con lualatex sarà probabilmente possibile in futuro (quando linterfaccia sarà più stabile) creare font virtuali ricodificati sul- fly, attualmente dovrebbe essere già possibile farlo con un file feature.
Answer
Questa è unestensione di @egreg “s answer utilizzando unaltra risposta di @egreg.
Con questo codice puoi inserire unintera frase in \censor
e tutte le parole inizialmente aggiunte a un elenco utilizzando \addcensor
sono sostituite da grawlixes. Largomento di \addcensor
può essere parola singola o elenco separato da virgole.
\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}
Commenti
- Mi infastidisce quando usi il posizionamento tradizionale di open e parentesi graffa di chiusura (parentesi graffa aperta adiacente alla funzione, quindi nuova riga, quindi il codice e infine la sola parentesi graffa di chiusura in una nuova riga —senza rientro—), mescolandola con il modo LaTeX3 consigliato (entrambi da soli su una nuova riga, rientrato della stessa quantità di spazio).
- @Manuel Spiacenti, Spero che la mia risposta aggiornata si adatti allo stile consigliato.
- Decisamente migliore (IMO). Mi piace così, anche ora che ‘ sto leggendo il codice sorgente di ConTeXt e scrive in modo completamente diverso (almeno non ‘ uso la parentesi graffa di apertura, la nuova riga, il codice, la parentesi graffa di chiusura della nuova riga senza indentazione troppo, ma qualcosa di più simile a
%
, nuova riga, parentesi graffa e codice di apertura, altro codice e parentesi graffa di chiusura successiva al codice).