Załóżmy, że chciałbym ocenzurować przekleństwo <word> za pomocą grawliksy , np „Co do licha # @ $! Robisz ?!” Jak mogę zdefiniować polecenie \censor takie, że \censor{<word>} skutkuje ciągiem tych symboli? Nie jestem do końca pewien, których lub ilu symboli należy użyć, biorąc pod uwagę słowo <word>. Przypuszczam, że liczba użytych symboli powinna w przybliżeniu odpowiadać liczbie znaków w <word>.

Dziękujemy za wkład!

Komentarze

  • Jest to dużo łatwiejsze w źródle edytora tekstu niż w TeX. (luatex jest prawdopodobnie łatwiejszy niż klasyczny tex, jeśli naprawdę chcesz to zrobić na poziomie tekstu) (Jest to dość łatwe do zrobienia w ograniczonych kontekstach tekstowych, ale trudne, jeśli musisz to zrobić w dowolnych akapitach i listach itp.) >
  • zobacz także tex.stackexchange.com/questions/88394/…
  • @percusse I # @ $! &%? !% $ @!% $.
  • @GonzaloMedina Czy mogę kupić samogłoskę?
  • Cóż, przynajmniej Dziś nauczyłem się nowego słowa . Ale dlaczego nie ' nie jest liczba mnoga grawliców ?

Odpowiedź

Losowy symbol jest pobierany z listy i dołączany do listy tokenów; kiedy szerokość skumulowanych symboli jest większa niż szerokość słowa minus 2 punkty, symbole są drukowane, w przeciwnym razie dołączany jest inny 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} 

tutaj wprowadź opis obrazu

Odpowiedź

Skromna próba z lualatex:

Kod zastępczy jest bardzo naiwny, potrzebowalibyśmy czegoś solidniejszego.

\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} 

Wynik:

Więcej kaczek

Morał historia: Nie potrafię opowiadać historii. :)

Teraz dodajmy grawliksy . Ponieważ potrzebuję lepszego kodu Lua, stwórzmy zewnętrzny plik censor.lua i wywołajmy go z .tex kodu:

\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} 

Wynik:

Grawlixes

Morał nowej historii: dodanie grawliksów do tekstu sprawia, że wygląda on niegrzecznie. :)

Komentarze

  • +1 (mimo że miałem nadzieję zobaczyć zdjęcie kaczki, być może zostało ocenzurowane?)

Odpowiedź

Pomijając zalety i wady tego, jak i dlaczego to zrobić, uważam, że jest to niezłe ćwiczenie związane z xstring . Oto moje podejście:

\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} 

Jak widać, ograniczenie polega na tym, że grawlix będzie składał się z tego samego zestawu znaków, w tej samej kolejności. (Możesz przedefiniować zestaw znaków lub znaleźć sposób na ich losowanie przy każdym wywołaniu makra … ale to inna historia! ;)) Ale twój grawlix będzie tak długi jako ocenzurowane słowo.

Dzieje się tak, że xstring ma swoje własne sposoby rozszerzania argumentów i makra nie mogą być zagnieżdżane. Wynik z makra, które znajduje długość ocenzurowanego słowa jest zwracana w innym makrze (nazywanym tutaj w wyobraźni \result), które zostanie (ponownie) użyte do podzielenia wstępnie zdefiniowanego \grawlix we właściwym miejscu.

Makro \expandarg zapewnia prawidłowe rozwinięcie. Zgodnie z xstring dokumentacji, pozwoli to na rozwinięcie wszystkich przekazanych argumentów dokładnie raz. Dlatego należy zachować ostrożność, aby chronić grupy, które reprezentują pojedynczy znak z nawiasami klamrowymi (np. \sharp symbol żyje w trybie matematycznym, ale nie chcemy t ograniczające go znaki dolara są postrzegane jako oddzielne tokeny).

Komentarze

  • Nie ' myślę, że \makeatletter i \makeatother są potrzebne wokół @ … Może być użyty jako symbol od razu.
  • @cgnieder It ' to dobra robota, nie są one konieczne, ponieważ nie mają żadnego efektu, jeśli są używane wewnątrz definicji, jak tutaj: – )
  • @DavidCarlisle prawda, nie ' o tym nie myślałem … Potrzebuję więcej kawy

Odpowiedź

Zwykłe rozwiązanie TeX-a bez dodatkowych pakietów, oparte na pomysłach Keesa van der Laana.

\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} 

Prawdopodobnie chcesz, aby wynik był powiązany z użytym słowem.W tym rozwiązaniu jest to \lccode znaku modulo 7. Możesz napisać albo

 \fifo censored \ofif 

lub, zgodnie z sugestią (przepraszam za mój język),

\censor{fuck} \censor{WORD} it is \censor{shit} 

uzyskiwanie

tutaj wprowadź opis obrazu

Kilka wyjaśnień. Głównym narzędziem jest implementacja kolejki FIFO (First-In-First-Out) zasugerowana przez Keesa van der Laana:

\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi} 

\fifo polecenie wywołuje makro \process, które obsługuje poszczególne argumenty. Każdy token jest przetwarzany do \ofif.

Reszta jest prosta. Manipulując licznikami \cur i \cura otrzymujemy liczbę od 0 do 6 i \ifcase przyjmuje różne znaki cenzora dla różnych wartości.

Uwaga. Jestem bardzo zainteresowany prawdziwymi regułami ( jeśli istnieją) zamiany przekleństw na ciągi symboli podobnych do @.

Komentarze

  • Bardzo fajnie. Czy mógłbyś nieco rozwinąć (przepraszam za kalambur), jak faktycznie działa kod?
  • @AlanMunn Tak, ale po powrocie do domu (późnym wieczorem).
  • \censor{MSWORD}

Odpowiedź

Stabilnym sposobem wymiany symboli jest zmiana kodowania czcionki lub aby ponownie zakodować czcionkę. Prosty przykład

\documentclass{article} \begin{document} \newcommand\censor[1]{\fontencoding{OMS}\selectfont #1} \censor{Censored} \end{document} 

Dzięki lualatex w przyszłości (gdy interfejs będzie bardziej stabilny) prawdopodobnie będzie możliwe tworzenie wirtualnych, ponownie zakodowanych czcionek on-the- fly, obecnie powinno być już możliwe zrobienie tego z plikiem funkcji.

Odpowiedź

To jest rozszerzenie @egreg „s answer używając innej odpowiedzi autorstwa @egreg.

Za pomocą tego kodu możesz wprowadzić całe zdanie w \censor i wszystkie słowa dodane początkowo do listy za pomocą \addcensor są zastępowane grawliksami. Argumentem \addcensor może być pojedyncze słowo lub lista oddzielona przecinkami.

\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} 

wprowadź opis obrazu tutaj

Komentarze

  • Denerwuje mnie, gdy używasz tradycyjnego umieszczania otwartych i nawias zamykający (otwarty nawias przylegający do funkcji, następnie nowy wiersz, następnie kod, a następnie sam nawias zamykający w nowym wierszu – bez wcięcia -), mieszając go z zalecanym sposobem LaTeX3 (oba same w nowym wierszu, z wcięciem o taką samą wielkość).
  • @Manuel Przepraszamy, Mam nadzieję, że moja zaktualizowana odpowiedź pasuje do zalecanego stylu.
  • Zdecydowanie lepiej (IMO). Podoba mi się ten sposób, nawet teraz, gdy ' czytam kod źródłowy ConTeXt i pisze on zupełnie inaczej (przynajmniej nie ' nie używam nawias otwierający, nowy wiersz, kod, nawias zamykający nowy wiersz bez zbyt dużego wcięcia, ale coś bardziej jak %, nowy wiersz, nawias otwierający i kod, więcej kodu i następny nawias zamykający do kodu).

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *