TeX, 216 байт (4 рядки, 54 символи в кожному)
Оскільки мова не йде про кількість байтів, а про якість виводу набору :-)
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
Спробуйте в Інтернеті! (Наверху; не впевнений, як це працює)
Повний тестовий файл:
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
\S{swap the a first and last letters of each word}
pwas eht a tirsf dna tasl setterl fo hace dorw
\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}
\bye
Вихід:

Для LaTeX вам просто потрібна плита котла:
\documentclass{article}
\begin{document}
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
\S{swap the a first and last letters of each word}
pwas eht a tirsf dna tasl setterl fo hace dorw
\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}
\end{document}
Пояснення
TeX - дивний звір. Читання нормального коду та розуміння його - це подвиг сам по собі. Розуміння прихованого коду TeX йде на кілька кроків далі. Я спробую зробити це зрозумілим для людей, які також не знають TeX, тому, перш ніж ми розпочнемо, ось декілька понять про TeX, щоб полегшити їх виконання:
Для (не дуже) абсолютних початківців TeX
По-перше, і найважливіший пункт цього списку: код не повинен бути у формі прямокутника, навіть якщо поп-культура може привести вас до цього .
TeX - мова розширення макросу. Ви можете, наприклад, визначити, \def\sayhello#1{Hello, #1!}а потім написати, \sayhello{Code Golfists}щоб TeX надрукував Hello, Code Golfists!. Це називається "неозначений макрос", і щоб подати його перший (і єдиний, у цьому випадку) параметр, ви вкладете його в дужки. TeX видаляє ці дужки, коли макрос захоплює аргумент. Ви можете використовувати до 9 параметрів: \def\say#1#2{#1, #2!}тоді \say{Good news}{everyone}.
Аналог неделімітованій макросів, що ні дивно, роздільники з них :) Ви можете зробити попереднє визначення трохи більше семантичним : \def\say #1 to #2.{#1, #2!}. У цьому випадку за параметрами слідує так званий текст параметра . Такий параметр тексту розмежовує аргумент макросу ( #1розмежований ␣to␣, пробілами включено і #2розмежовано на .). Після цього визначення ви можете написати \say Good news to everyone., яке розшириться до Good news, everyone!. Приємно, чи не так? :) Однак обмежений аргумент - це (цитуючи TeXbook ) "найкоротшу (можливо, порожню) послідовність лексем з правильно вкладеними {...}групами, за якими вводиться цей конкретний список жетонів, що не мають параметрів". Це означає, що розширення\say Let's go to the mall to Martinвиробить дивне речення. В цьому випадку вам потрібно «приховати» перший ␣to␣з {...}: \say {Let's go to the mall} to Martin.
Все йде нормально. Тепер все починає набувати дивного характеру. Коли TeX читає символ (який визначається "кодом символу"), він призначає цьому символу "код категорії" (кодовий код для друзів :), який визначає, що буде означати цей символ. Таке поєднання характеру і категорії коду робить маркер (більше на тому , що тут , наприклад). Ці, які тут нас цікавлять, це:
catcode 11 , який визначає лексеми, які можуть складати контрольну послідовність (шикарне ім'я для макросу). За замовчуванням усі літери [a-zA-Z] є кодовим кодом 11, тому я можу писати \hello, що є однією єдиною керуючою послідовністю, тоді \he11oяк керуюча послідовність \heз двома символами 1, а потім літера o, тому що 1це не кодовий код 11. Якщо я зробив \catcode`1=11, з цього моменту \he11oбуде одна контрольна послідовність. Важливим є те, що кодові коди встановлюються, коли TeX вперше бачить персонажа під рукою, і такий кодовий код заморожений ... ЗАВЖДИ! (можуть застосовуватися умови)
кодовий код 12 , який є більшістю інших символів, таких як 0"!@*(?,.-+/тощо. Вони є найменш особливим типом кодового коду, оскільки вони служать лише для написання матеріалів на папері. Але ей, хто використовує TeX для написання?!? (знову ж, можуть застосовуватися умови)
catcode 13 , що пекло :) Дійсно. Перестань читати і йди робити щось із свого життя. Ви не хочете знати, що таке кодовий код 13. Коли-небудь чули про п’ятницю, 13-го? Здогадайтесь, звідки вона отримала свою назву! Продовжуйте на власний ризик! Символ коду 13, який ще називають "активним" символом, вже не просто символ, це сам макрос! Ви можете визначити його з параметрами та розгорнути на щось подібне, що ми бачили вище. Після того як \catcode`e=13ви думаєте, що можете зробити \def e{I am the letter e!}, АЛЕ ТИ. КАННОТ! eце вже не лист, так \defце не \defви знаєте, це \d e f! О, виберіть інший лист, який ви говорите? Гаразд! \catcode`R=13 \def R{I am an ARRR!}. Дуже добре, Джиммі, спробуй! Я смію це зробити і написати Rсвій код! Ось що таке кодовий код 13. Я - КЛАМ! Перейдемо далі.
Гаразд, зараз до групування. Це досить просто. Незалежно від призначення ( \defце операція з присвоєнням, \let(ми ввійдемо в неї) - це інша), яка виконується в групі, відновлюються до того, що вони були до початку цієї групи, якщо це призначення не є глобальним. Існує кілька способів запустити групи, один з них - з кодовим кодом 1 і 2 символи (о, знову ж таки коди). За замовчуванням {це кодовий код 1, або початкова група, і }це кодовий код 2, або кінцева група. Приклад: \def\a{1} \a{\def\a{2} \a} \aЦе відбитки 1 2 1. Поза групою \aбула 1, потім всередині була перероблена 2, і коли група закінчилася, вона була відновлена 1.
\letОперація інша операція присвоювання , як \def, а по- іншому. З \defви визначити макроси , які будуть розширювати , щоб матеріал, з \letстворенням копії вже існуючих речей. Після \let\blub=\def( =необов’язково) ви можете змінити початок eприкладу з кодового коду 13 пункту вище на \blub e{...та розважитися цим. Або краще, замість того , щоб ламати речі можна виправити (ви подивіться на це!) На Rприклад: \let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}. Швидке запитання: чи могли ви перейменувати \newR?
Нарешті, так звані «помилкові простори». Це своєрідна тема табу, оскільки є люди, які стверджують, що репутація, зароблена на біржі стеків TeX - LaTeX , відповідаючи на "помилкові місця", не повинна розглядатися, а інші відверто не згодні. З ким ти згоден? Розмістіть свої ставки! Тим часом: TeX розуміє розрив лінії як пробіл. Спробуйте написати кілька слів з перервою рядка (не порожнім рядком ) між ними. Тепер додайте а %в кінці цих рядків. Це все одно, що ви "коментували" ці пробіли в кінці рядка. Це воно :)
(Сортування) скасування коду
Давайте зробимо цей прямокутник у чомусь (можливо) простішим:
{
\let~\catcode
~`A13
\defA#1{~`#113\gdef}
AGG#1{~`#113\global\let}
GFF\else
GHH\fi
AQQ{Q}
AII{\ifxQ}
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
ADD#1#2#3|{I#2FE{#1}#2#3|H}
ACC#1#2|{D{}#2Q|#1 }
ABBH#1 {HI#1FC#1|BH}
\gdef\S#1{\iftrueBH#1 Q }
}
Пояснення кожного кроку
кожен рядок містить одну єдину інструкцію. Ходімо по черзі, розбираючи їх:
{
Спочатку ми запускаємо групу, щоб зберегти деякі зміни (а саме зміни кодового коду) локальними, щоб вони не зіпсували вхідний текст.
\let~\catcode
В основному всі коди обфускування TeX починаються з цієї інструкції. За замовчуванням, як у звичайному TeX, так і в LaTeX, ~символ є одним активним символом, який може бути перетворений в макрос для подальшого використання. І найкращим інструментом для присвоєння коду TeX є зміни кодового коду, тому це, як правило, найкращий вибір. Тепер замість цього \catcode`A=13ми можемо написати ~`A13( =необов’язково):
~`A13
Тепер лист Aє активним символом, і ми можемо визначити його, щоб зробити щось:
\defA#1{~`#113\gdef}
Aтепер макрос, який бере один аргумент (який повинен бути іншим символом). Спочатку кодовий аргумент змінюється на 13, щоб він став активним: ~`#113(замініть на ~, \catcodeдодайте =і у вас є :) \catcode`#1=13. Нарешті, він залишає \gdef(глобальним \def) у вхідному потоці. Коротше кажучи, Aробить іншого персонажа активним і починає його визначення. Давайте спробуємо:
AGG#1{~`#113\global\let}
AGспочатку "активується" Gі робить \gdef, після чого наступне Gпочинає визначення. Визначення Gдуже схоже на визначення цього A, за винятком того, що замість \gdefнього робиться \global\let(немає \gletподібного \gdef). Словом, Gактивізує персонажа і робить його чимось іншим. Зробимо ярлики для двох команд, які ми використаємо пізніше:
GFF\else
GHH\fi
Тепер замість \elseі \fiми можемо просто використовувати Fі H. Набагато коротше :)
AQQ{Q}
Тепер ми використовуємо Aще раз , щоб визначити інший макрос, Q. Вищенаведене твердження в основному робить (менш заплутаною мовою) \def\Q{\Q}. Це не дуже цікаве визначення, але воно має цікаву особливість. Якщо ви не хочете зламати якийсь код, єдиний макрос, який розширюється, - Qце Qсам, тому він діє як унікальний маркер (його називають кварком ). Ви можете використовувати \ifxумовне для перевірки, чи аргумент макросу такий кварк із \ifx Q#1:
AII{\ifxQ}
тож ви можете бути впевнені, що знайшли такий маркер. Зауважте, що в цьому визначенні я видалив пробіл між \ifxі Q. Зазвичай це призведе до помилки (зауважте, що синтаксис підкреслює, що \ifxQце одне), але оскільки Qце кодовий код 13, він не може сформувати контрольну послідовність. Але будьте обережні, щоб не розширювати цей кварк, або ви застрягнете у нескінченному циклі, оскільки Qрозширюється, до Qякого розширюється, до Qякого ...
Тепер, коли попередні випуски зроблені, ми можемо перейти до відповідного алгоритму, щоб задати сеттерл. Завдяки токенізації TeX алгоритм повинен записуватися назад. Це тому, що під час виконання визначення TeX буде токенізувати (призначити кодові коди) символам у визначенні, використовуючи поточні настройки, наприклад, якщо я це роблю:
\def\one{E}
\catcode`E=13\def E{1}
\one E
Вихід є E1, тоді як якщо я зміню порядок визначень:
\catcode`E=13\def E{1}
\def\one{E}
\one E
вихід є 11. Це тому, що в першому прикладі визначення Eу токенізації було позначене буквою (кодовий код 11) до зміни кодового коду, тому це завжди буде буквою E. У другому прикладі, однак, Eспочатку було активовано, і лише потім \oneбуло визначено, і тепер визначення містить кодовий код 13, Eякий розширюється на 1.
Я, однак, не помічаю цього факту і переставляю визначення, щоб вони мали логічний (але не працює) порядок. У наступних параграфах ви можете припустити , що букви B, C, Dі Eє активними.
\gdef\S#1{\iftrueBH#1 Q }
(зауважте, що в попередній версії була невелика помилка, вона не містила остаточного пробілу у визначенні вище. Я помітив її лише під час написання цього запиту. Читайте далі, і ви побачите, чому нам потрібен той, щоб правильно припинити макрос. )
Спочатку ми визначаємо призначені для користувача макроси, \S. Цей не повинен бути активним символом, щоб мати дружній (?) Синтаксис, тому макрос для gwappins eht setterl є \S. Макрос починається з завжди справжнього умовного \iftrue(незабаром стане зрозуміло, чому), а потім викликає Bмакрос, за яким H(який ми визначили раніше \fi), щоб відповідати \iftrue. Потім залишаємо аргумент макросу, #1після якого пробіл і кварк Q. Припустимо, ми використовуємо \S{hello world}тоді вхідний потікмає виглядати приблизно так: \iftrue BHhello world Q␣(Я замінив останній пробіл ␣таким, щоб візуалізація сайту не з'їла його, як це було в попередній версії коду). \iftrueце правда, тому вона розширюється, і ми залишаємося BHhello world Q␣. TeX це НЕ видалити \fi( H) після того , як умовно оцінюється, замість цього вона залишає його там , поки \fiНЕ буде на самому ділі розширюється. Тепер Bмакрос розгорнуто:
ABBH#1 {HI#1FC#1|BH}
Bце обмежений макрос, чий текст параметру є H#1␣, тому аргументом є все, що знаходиться між Hі пробілом. Продовжуючи приклад вище вхідного потоку перед розширенням BIS BHhello world Q␣. Bслідує H, як слід (інакше TeX призведе до помилки), тоді наступний пробіл знаходиться між helloі world, #1як і слово hello. І ось ми ділимо ввідний текст на пробіли. Yay: D Розширення Bвидаляє всі аж до першого місця з вхідного потоку і замінює на HI#1FC#1|BHс #1того hello: HIhelloFChello|BHworld Q␣. Зауважте, що є новий BHпізніше у вхідному потоці, щоб зробити хвостову рекурсіюBі обробляти пізніші слова. Після обробки цього слова обробляє Bнаступне слово, поки слово, яке підлягає обробці, не стане кварком Q. Останній пробіл після Qпотрібен, тому що для розмежованого макросу B потрібен один в кінці аргументу. З попередньою версією (див. Історію редагування) код не буде поводитись, якщо ви використовували \S{hello world}abc abc(проміжок між abcs зникне).
OK, назад у вхідний потік: HIhelloFChello|BHworld Q␣. Спочатку є H( \fi), що завершує початкове \iftrue. Тепер у нас це є (псевдокодування):
I
hello
F
Chello|B
H
world Q␣
Думка I...F...H- це насправді \ifx Q...\else...\fiструктура. У \ifxтест перевіряє , є чи (перший токен) слово схопив є Qкварк. Якщо немає нічого іншого, і виконання завершується, в іншому випадку що залишається: Chello|BHworld Q␣. Зараз Cрозширено:
ACC#1#2|{D#2Q|#1 }
Перший аргумент Cє НЕ виділяються, так що якщо не приготувався буде один маркер, другий аргумент обмежений |, так що після розширення C(з #1=hі #2=ello) вхідний потік: DelloQ|h BHworld Q␣. Зверніть увагу , що інший |ставляться там, і hз helloставляться після цього. Половина заміни робиться; перша буква - в кінці. У TeX легко схопити перший маркер списку токенів. Простий макрос \def\first#1#2|{#1}отримує першу літеру при використанні \first hello|. Останнє - це проблема, оскільки TeX завжди сприймає "найменший, можливо, порожній" список лексем як аргумент, тому нам потрібно кілька обхідних завдань. Наступний пункт у списку токенів D:
ADD#1#2|{I#1FE{}#1#2|H}
Цей Dмакрос є одним із найрізноманітніших і корисний у єдиному випадку, коли слово має одну букву. Припустимо, замість helloнас x. У цьому випадку потік введення буде DQ|x, а потім Dрозшириться (із #1=Qта #2порожнім) до:IQFE{}Q|Hx . Це аналогічно блоку I...F...H( \ifx Q...\else...\fi) в B, який побачить, що аргументом є кварк і перерве виконання, залишаючи лише xдля набору тексту. В інших випадках (повернення до helloприкладу), Dбуде розширюватися (з #1=eі #2=lloQ) за адресою: IeFE{}elloQ|Hh BHworld Q␣. Знову ж , I...F...Hбуде перевіряти , Qале зазнає невдачі і взяти \elseвладу: E{}elloQ|Hh BHworld Q␣. Тепер останній фрагмент цієї речіE макрос розшириться:
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
Текст параметра тут досить схожий на Cта D; перший і другий аргументи не визнаються, а останній розміщений на |. Вхідний потік виглядає наступним чином : E{}elloQ|Hh BHworld Q␣, потім Eрозширюється (з #1порожнім, #2=eі #3=lloQ): IlloQeFE{e}lloQ|HHh BHworld Q␣. Інший I...F...Hблок перевіряє кварк (який бачить lі повертається false): E{e}lloQ|HHh BHworld Q␣. Тепер Eзнову розгортається (з #1=eпорожнім,#2=l і #3=loQ): IloQleFE{el}loQ|HHHh BHworld Q␣. І знову I...F...H. Макрос робить ще кілька ітерацій, поки Qнарешті не знайдено і не trueбуде взято гілку: E{el}loQ|HHHh BHworld Q␣-> IoQlelFE{ell}oQ|HHHHh BHworld Q␣-> E{ell}oQ|HHHHh BHworld Q␣-> IQoellFE{ello}Q|HHHHHh BHworld Q␣. Тепер кварк знайдений і умовні Розкривається в: oellHHHHh BHworld Q␣. Phew.
Ой, чекай, що це? НОРМАЛЬНІ ЛИСТИ? О, малюк! Листи , нарешті , знайшли і TeX запише oell, то зв'язка H( \fi) будуть знайдені і розширені (нічого) , що виходить з вхідного потоку з: oellh BHworld Q␣. Тепер у першому слові поміняються перша і остання букви, і теХ, що знаходить наступне, - друге, Bщоб повторити весь процес для наступного слова.
}
Нарешті ми закінчуємо групу, розпочату туди, щоб усі місцеві завдання були скасовані. Місцеві призначення є catcode зміни букв A, B, C, ... , які були зроблені макроси так , що вони повертаються до свого нормального значення букви і може безпечно використовуватися в тексті. І це все. Тепер \Sвизначений там макрос запустить обробку тексту, як зазначено вище.
Цікавою справою цього коду є те, що він повністю розширюється. Тобто, ви можете сміливо використовувати його в рухомих аргументах, не переживаючи, що він вибухне. Ви навіть можете скористатися кодом, щоб перевірити, чи остання буква слова однакова другої (з будь-якої причини, що вам знадобиться) у \ifтесті:
\if\S{here} true\else false\fi % prints true (plus junk, which you would need to handle)
\if\S{test} true\else false\fi % prints false
Вибачте за (мабуть, занадто) багатослівне пояснення. Я намагався зробити це максимально зрозумілим і для не TeXies :)
Підсумок для нетерплячих
Макрос \Sпопередньо вводить активний символ, Bякий захоплює списки жетонів, обмежених остаточним пробілом, і передає їх C. Cбере перший маркер у цьому списку і переміщує його до кінця списку токенів і розширює Dтим, що залишилося. Dперевіряє, чи "те, що залишається" порожнє, і в цьому випадку знайдено однолітерне слово, тоді не робіть нічого; інакше розширюється E. Eпробирається через список токенів, поки він не знайде останню букву в слові, і коли він знайдеться, він залишає останню букву з наступною серединою слова, після чого слідує перша буква, залишена в кінці потоку лексеми від C.
Hello, world!стає,elloH !orldw(міняючи розділові знаки як літеру) чиoellH, dorlw!(тримаючи розділові знаки на місці)?