Suponha que eu gostaria de censurar um palavrão <word>
usando grawlixes , por exemplo “O que diabos você está fazendo ?!” Como posso definir um comando \censor
de forma que \censor{<word>}
resulte em uma sequência desses símbolos? Não estou totalmente certo de quais ou quantos símbolos devem ser usados com a palavra <word>
. Suponho que o número de símbolos usados deve ser aproximadamente igual ao número de caracteres em <word>
.
Obrigado por sua entrada!
Comentários
- É muito mais fácil fazer isso no código-fonte do editor de texto do que no TeX. (luatex é provavelmente mais fácil do que o tex clássico se você realmente quiser fazer no nível do texto) (É fácil o suficiente fazer em contextos de texto restritos, mas difícil se você precisar fazê-lo em parágrafos arbitrários e listas, etc)
- veja também tex.stackexchange.com/questions/88394/…
- @percusse I # @ $! &%? !% $ @!% $.
- @GonzaloMedina Posso comprar uma vogal?
- Bem, pelo menos Aprendi uma nova palavra hoje. Mas por que não ' t o plural grawlices ?
Resposta
Um símbolo aleatório é retirado de uma lista e anexado a uma lista de tokens; quando a largura dos símbolos acumulados é maior do que a largura da palavra menos 2pt, os símbolos são impressos, caso contrário, outro símbolo é anexado.
\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}
Resposta
Uma humilde tentativa com lualatex
:
O código de substituição é muito ingênuo, precisaríamos de algo mais 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}
O resultado:
Moral de a história: Sou péssimo em contar histórias. :)
Agora, vamos adicionar os grawlixes . Como preciso de um código Lua melhor, vamos criar um arquivo externo censor.lua
e chamá-lo de fora do .tex
código:
\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}
O resultado:
Moral da nova história: adicionar grawlixes a um texto faz com que pareça impertinente. :)
Comentários
- +1 (embora eu esperasse ver uma foto de pato, talvez tenha sido censurada?)
Resposta
Deixando de lado os prós e contras de como e por que fazer isso, acho que é um pequeno exercício agradável para fazer com xstring
. Então, aqui está minha opinião sobre isso:
\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}
Como você pode ver, a limitação é que o grawlix será composto do mesmo conjunto de caracteres, na mesma ordem. (Você pode redefinir o conjunto de caracteres ou encontrar uma maneira de randomizá-los a cada invocação da macro … mas essa é uma história diferente! ;)
) Mas seu grawlix será tão longo como a palavra censurada.
O que acontece é que xstring
tem suas próprias maneiras de expandir argumentos e as macros não podem ser aninhadas. Portanto, o resultado da macro que encontra o comprimento da palavra censurada é retornado em uma macro diferente (imaginativamente chamada aqui \result
) que será (re) usada para dividir o \grawlix
no local certo.
A macro \expandarg
garante que a expansão seja feita corretamente. De acordo com xstring
documentação, ele permitirá que todos os argumentos passados sejam expandidos exatamente uma vez. Portanto, deve-se tomar cuidado para proteger os grupos que representam um único caractere com colchetes (por exemplo, o \sharp
o símbolo vive no modo matemático, mas não queremos os cifrões que o delimitam para serem vistos como tokens separados).
Comentários
- Eu não ' ache que
\makeatletter
e\makeatother
são necessários em torno do @ … Ele pode ser usado como o símbolo que é imediatamente. - @cgnieder É ' um bom trabalho, eles não são necessários, pois não têm nenhum efeito se usados dentro da definição aqui: – )
- @DavidCarlisle true, não ' pensei nisso … preciso de mais café
Resposta
Uma solução TeX simples sem pacotes adicionais, com base nas ideias de 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}
Você provavelmente deseja que o resultado seja conectado à palavra usada.Nesta solução, é \lccode
de um módulo de caractere 7. Você pode escrever
\fifo censored \ofif
ou, conforme sugerido (desculpe meu idioma),
\censor{fuck} \censor{WORD} it is \censor{shit}
obtendo
Algumas explicações. A principal ferramenta é a implementação da fila FIFO (First-In-First-Out) sugerida por Kees van der Laan:
\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi}
O \fifo
comando chama uma macro \process
que trata os argumentos individuais. Cada token é processado até \ofif
.
O resto é simples. Manipulando nos contadores \cur
e \cura
, obtemos um número entre 0 e 6 e \ifcase
usa caracteres de censura diferentes para valores diferentes.
Observação. Estou muito interessado nas regras reais ( se existirem) de substituir palavrões por strings de símbolos do tipo @.
Comentários
- Muito bom. Você poderia talvez expandir (com o perdão do trocadilho) um pouco sobre como o código realmente funciona?
- @AlanMunn Sim, mas depois de voltar para casa (tarde da noite).
-
\censor{MSWORD}
Resposta
Uma maneira estável de trocar símbolos é mudar a codificação da fonte ou para recodificar a fonte. Um exemplo simples
\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document}
Com lualatex, será provavelmente possível no futuro (quando a interface for mais estável) criar fontes virtuais recodificadas no voar, atualmente já deve ser possível fazê-lo com um arquivo de feição.
Resposta
Esta é uma extensão de @egreg “s resposta usando outra resposta de @egreg.
Com este código, você pode inserir uma frase inteira em \censor
e todas as palavras inicialmente adicionadas a uma lista usando \addcensor
são substituídas por grawlixes. O argumento para \addcensor
pode ser um palavra única ou uma lista separada por vírgulas.
\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}
Comentários
- Fico irritada quando você usa a colocação tradicional de aberto e a chave de fechamento (abra a chave adjacente à função, depois a nova linha, o código e a chave de fechamento sozinha em uma nova linha —sem indentação—), misturando-a com o método LaTeX3 recomendado (ambos isolados em uma nova linha recuou a mesma quantidade de espaço).
- @Manuel Desculpe, Espero que minha resposta atualizada se encaixe no estilo recomendado.
- Definitivamente melhor (IMO). Gosto dessa forma, mesmo agora que ' estou lendo o código-fonte do ConTeXt e ele escreve de maneira completamente diferente (pelo menos eles ' não usam a chave de abertura, nova linha, código, chave de fechamento de nova linha sem muito recuo, mas algo mais como
%
, nova linha, chave de abertura e código, mais código e chave de fechamento a seguir ao código).