Antag att jag skulle vilja censurera ett förbannningsord <word>
med grawlixes , t.ex. ”Vad # # $! Gör du ?!” Hur kan jag definiera ett kommando \censor
så att \censor{<word>}
resulterar i en sträng av dessa symboler? Jag är inte helt säker på vilka eller hur många symboler som ska användas med tanke på ordet <word>
. Jag antar att antalet använda symboler ungefär ska vara lika med antalet tecken i <word>
.
Tack för din inmatning!
Kommentarer
- Det är mycket lättare att göra det i textredigerarkällan än i TeX. (luatex är förmodligen enklare än klassisk tex om du verkligen vill göra det på textnivå) (Det är tillräckligt enkelt att göra det i begränsade textkontexter men svårt om du behöver göra det i godtyckliga stycken och listor etc)
- se även tex.stackexchange.com/questions/88394/…
- @percusse I # @ $! &%? !% $ @!% $.
- @GonzaloMedina Kan jag köpa en vokal?
- Tja, åtminstone Jag lärde mig ett nytt ord idag. Men varför är inte ’ t plural grawlices ?
Svar
En slumpmässig symbol tas från en lista och läggs till en tokenlista; när bredden på de ackumulerade symbolerna är större än ordets bredd minus 2pt, skrivs symbolerna ut, annars läggs en annan symbol till.
\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
Ett ödmjukt försök med lualatex
:
Ersättningskoden är väldigt naiv, vi skulle behöva något mer 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}
Utgången:
Moral av berättelsen: Jag är hemskt på att berätta historier. :)
Nu, låt oss lägga till grawlixerna . Eftersom jag behöver en bättre Lua-kod, låt oss skapa en extern fil censor.lua
och kalla den från .tex
-kod:
\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}
Utgången:
Moralen i den nya berättelsen: att lägga till grawlixer i en text gör att det ser styggt ut. :)
Kommentarer
- +1 (även om jag hoppades på att se en anka, kanske den censurerades?)
Svar
Bortsett från fördelarna och nackdelarna med hur och varför man gör det, tycker jag att det är en trevlig liten övning att göra med xstring
. Så här är min åsikt 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 är begränsningen att grawlix kommer att bestå av samma uppsättning tecken i samma ordning. (Du kan omdefiniera teckenuppsättningen eller hitta ett sätt att randomisera dem vid varje anrop av makrot … men det är en annan historia! ;)
) Men din grawlix kommer att vara lika lång som det censurerade ordet.
Vad som händer är att xstring
har sina egna sätt att expandera argument och makron kan inte kapslas. Så resultatet från makrot som hittar längden på det censurerade ordet returneras i ett annat makro (fantasifullt kallat här \result
) som kommer att (åter) användas för att dela den fördefinierade \grawlix
på rätt plats.
\expandarg
makrot ser till att expansionen görs ordentligt. Enligt xstring
dokumentation, kommer det att tillåta att alla givna argument utvidgas exakt en gång. Därför måste man vara försiktig med att skydda grupper som representerar ett enstaka tecken med parenteser (t.ex. = ”d271e5b792”>
-symbolen bor i mathmod, men vi vill inte t dollartecknen som avgränsar det för att ses som separata tokens).
Kommentarer
- Jag don ’ t tror att
\makeatletter
och\makeatother
är nödvändiga runt @ … Det kan användas som en symbol det är direkt. - @cgnieder Det ’ ett bra jobb de är inte nödvändiga eftersom de inte har någon effekt alls om de används inuti definitionen som här: – )
- @DavidCarlisle sant, jag hade inte ’ tänkte på det … Jag behöver mer kaffe
Svar
En vanlig TeX-lösning utan ytterligare paket, baserat på idéer från 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 vill antagligen ha resultatet kopplat till det ord som används.I den här lösningen är det \lccode
av ett tecken modulo 7. Du kan skriva antingen
\fifo censored \ofif
eller, som föreslagit (ledsen för mitt språk),
\censor{fuck} \censor{WORD} it is \censor{shit}
får
Några förklaringar. Huvudverktyget är implanteringen av FIFO (First-In-First-Out) kö föreslagen av Kees van der Laan:
\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi}
\fifo
-kommandot anropar ett makro \process
som hanterar de enskilda argumenten. Varje token behandlas tills \ofif
.
Resten är enkel. Manipulering på räknarna \cur
och \cura
vi får ett tal mellan 0 och 6 och \ifcase
tar olika censurtecken för olika värden.
Anmärkning. Jag är mycket intresserad av de verkliga reglerna ( om de finns) för att ersätta förbannade ord med strängar med @liknande symboler.
Kommentarer
- Mycket trevligt. Kan du kanske utöka (ursäkta ordlistan) lite om hur koden faktiskt fungerar?
- @AlanMunn Ja, men efter att ha återvänt hem (sent på kvällen).
-
\censor{MSWORD}
Svar
Ett stabilt sätt att byta symboler är att ändra fontkodning eller för att återkoda teckensnittet. Ett enkelt exempel
\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document}
Med lualatex är det i framtiden (när gränssnittet är mer stabilt) möjligt att skapa virtuella återkodade teckensnitt på flyga, för närvarande borde det redan vara möjligt att göra det med en funktionsfil.
Svar
Detta är ett tillägg till @egreg ”s svar använder ett annat svar av @egreg.
Med den här koden kan du ange en hel mening i \censor
och alla ord som ursprungligen har lagts till i en lista med \addcensor
ersätts av grawlixes. Argumentet för \addcensor
kan antingen vara enstaka ord eller en kommaseparerad lista.
\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 irriterar mig när du använder traditionell placering av öppen och stängningsstöd (öppet stag intill funktionen, sedan ny rad, sedan koden och sedan stängningsstaget ensam i en ny rad – utan indrag -), blandar det med det rekommenderade LaTeX3-sättet (båda ensamma på en ny linje, indragade lika mycket utrymme).
- @Manuel Tyvärr, Jag hoppas att mitt uppdaterade svar passar den rekommenderade stilen.
- Definitly better (IMO). Jag gillar det här sättet, även nu när jag ’ läser ConTeXt-källkod och det skriver helt annorlunda (åtminstone använder de ’ öppningsstaget, ny rad, kod, ny radstängning utan fördjupning för mycket, men något mer som
%
, ny rad, öppningsstång och kod, mer kod och stängning nästa till koden).