Să presupunem că aș dori să cenzurăm un cuvânt blestem <word>
folosind grawlixes , de ex „Ce faci cu @ @ $! Faci ?!” Cum pot defini o comandă \censor
astfel încât \censor{<word>}
să conducă la un șir de aceste simboluri? Nu sunt pe deplin sigur care sau câte simboluri ar trebui folosite având în vedere cuvântul <word>
. Presupun că numărul de simboluri utilizate ar trebui să fie aproximativ egal cu numărul de caractere din <word>
.
Vă mulțumim pentru contribuție!
Comentarii
- Este mult mai ușor să faci asta în sursa editorului de text decât în TeX. (luatex este probabil mai ușor decât textul clasic dacă doriți cu adevărat să faceți acest lucru la nivel de text) (Este destul de ușor să faceți acest lucru în contexte de text restricționate, dar greu dacă trebuie să faceți acest lucru în paragrafe și liste arbitrare etc.)
- vezi și tex.stackexchange.com/questions/88394/…
- @percusse I # @ $! &%? !% $ @!% $.
- @GonzaloMedina Pot cumpăra o vocală?
- Ei bine, cel puțin Am învățat un cuvânt nou astăzi. Dar de ce nu este ‘ pluralul grawlices ?
Răspuns
Un simbol aleatoriu este preluat dintr-o listă și atașat la o listă de simboluri; când lățimea simbolurilor acumulate este mai mare decât lățimea cuvântului minus 2pt, simbolurile sunt tipărite, altfel se adaugă un alt simbol.
\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}
Răspunde
O umilă încercare cu lualatex
:
Codul de înlocuire este foarte naiv, am avea nevoie de ceva mai 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}
Rezultatul:
Morală de povestea: Sunt „teribil când povestesc. :)
Acum, să adăugăm grawlix-urile . Deoarece am nevoie de un cod Lua mai bun, să creăm un fișier extern censor.lua
și îl chemăm din .tex
cod:
\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}
Rezultatul:
Morala noii povești: adăugarea grawlix la un text îl face să pară obraznic. :)
Comentarii
- +1 (chiar dacă speram să văd o poză de rață, poate a fost cenzurată?)
Răspuns
Lăsând deoparte argumentele pro și contra cum și de ce să fac asta, mi se pare un mic exercițiu frumos de făcut cu xstring
. Așadar, iau ideea mea:
\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}
După cum puteți vedea, limitarea este că grawlix va fi compus din același set de caractere, în aceeași ordine. (Puteți redefini setul de caractere sau puteți găsi o modalitate de a le randomiza la fiecare invocare a macro-ului … dar asta este o poveste diferită! ;)
) Dar grawlix-ul dvs. va fi la fel de lung ca cuvânt cenzurat.
Ce se întâmplă este că xstring
are propriile sale modalități de a extinde argumentele și macro-urile nu pot fi imbricate. Deci, rezultatul din macro-ul care găsește lungimea cuvântului cenzurat este returnată într-o macro diferită (numită imaginativ aici \result
) care va fi (re) utilizată pentru a împărți \grawlix
la locul potrivit.
Macro-ul \expandarg
se asigură că extinderea se face corect. Conform xstring
documentație, va permite ca toate argumentele transmise să fie extinse exact o dată. Prin urmare, trebuie să aveți grijă să protejați grupurile care reprezintă un caracter unic cu paranteze (de exemplu, \sharp
simbolul trăiește în matematică, dar noi nu vrem t semnele dolarului care îl delimitează să fie văzute ca jetoane separate).
Comentarii
- Nu ‘ nu cred că
\makeatletter
și\makeatother
sunt necesare în jurul valorii de @ … Poate fi folosit ca simbol pe care este imediat. - @cgnieder Este ‘ o treabă bună, nu sunt necesare, deoarece nu au niciun efect dacă sunt folosite în definiția ca aici: – )
- @DavidCarlisle adevărat, nu m-am gândit ‘ la asta … Am nevoie de mai multă cafea
Răspuns
O soluție TeX simplă, fără pachete suplimentare, bazată pe ideile lui 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}
Probabil că doriți ca rezultatul să fie legat de cuvântul folosit.În această soluție este \lccode
al unui caracter modulo 7. Puteți scrie fie
\fifo censored \ofif
fie, așa cum este sugerat (îmi pare rău pentru limba mea),
\censor{fuck} \censor{WORD} it is \censor{shit}
obținerea
Câteva explicații. Instrumentul principal este implementarea cozii FIFO (First-In-First-Out) sugerată de Kees van der Laan:
\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi}
apelează o macro \process
care tratează argumentele individuale. Fiecare jeton este procesat până la \ofif
.
Restul este simplu. Manipulând pe contoare \cur
și \cura
obținem un număr între 0 și 6 și \ifcase
ia diferite caractere de cenzor pentru valori diferite.
Observație. Sunt foarte interesat de regulile reale ( dacă există) de înlocuire a cuvintelor blestemate cu șiruri de simboluri @ -like.
Comentarii
- Foarte frumos. Ați putea extinde (scuzați jocul de cuvinte) un pic despre modul în care funcționează codul?
- @AlanMunn Da, dar după întoarcerea acasă (seara târziu).
-
\censor{MSWORD}
Răspuns
O modalitate stabilă de a schimba simboluri este schimbarea codării fontului sau pentru a recodifica fontul. Un exemplu simplu
\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document}
Cu lualatex va fi probabil în viitor (când interfața este mai stabilă) să fie posibil să se creeze fonturi virtuale recodificate pe – fly, în prezent ar trebui să fie deja posibil să o faceți cu un fișier de caracteristici.
Răspuns
Aceasta este o extensie la @egreg „s răspuns folosind un alt răspuns de @egreg.
Cu acest cod puteți introduce o propoziție întreagă în \censor
și toate cuvintele adăugate inițial la o listă folosind \addcensor
sunt înlocuite cu grawlixes. Argumentul pentru \addcensor
poate fi un singur cuvânt sau o listă separată prin virgulă.
\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}
Comentarii
- Mă enervează când folosești plasarea tradițională a deschisului și dispozitivul de închidere (dispozitivul de deschidere adiacent funcției, apoi linia nouă, apoi codul și apoi dispozitivul de închidere singur într-o linie nouă – fără liniuță), amestecându-l cu modul LaTeX3 recomandat (ambele singure pe o linie nouă, a indentat aceeași cantitate de spațiu).
- @ Manuel Ne pare rău, Sper că răspunsul meu actualizat se potrivește stilului recomandat.
- Definitiv mai bine (IMO). Îmi place așa, chiar acum că ‘ m citesc codul sursă ConTeXt și scrie complet diferit (cel puțin nu folosesc ‘ paranteză de deschidere, linie nouă, cod, paranteză de închidere nouă fără prea mare indentare, dar ceva mai asemănător cu
%
, linie nouă, paranteză de deschidere și cod, mai mult cod și paranteză de închidere la cod).