TeX, 216 bayt (4 satır, her biri 54 karakter)
Bayt sayısıyla ilgili olmadığı için, dizgi çıktısının kalitesi ile ilgilidir :-)
{\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 }}
Çevrimiçi Deneyin! (Overleaf; nasıl çalıştığından emin değilim)
Tam test dosyası:
{\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
Çıktı:
LaTeX için sadece kazan plakasına ihtiyacınız var:
\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}
açıklama
TeX garip bir canavardır. Normal kodları okumak ve anlamak kendi başına bir başarıdır. Karışık TeX kodunu anlamak birkaç adım daha ileriye gider. Bunu TeX'i de bilmeyen insanlar için anlaşılabilir hale getirmeye çalışacağım, bu yüzden başlamadan önce TeX ile ilgili işleri takip etmeyi kolaylaştıran birkaç kavram:
(Öyle değil) mutlak TeX yeni başlayanlar için
İlk olarak, ve bu listede en önemli parça: Kod yok değil , dikdörtgen şeklinde olmak zorunda olsa bile pop kültürü götürebilir öyle düşünmek .
TeX bir makro genişleme dilidir. Örnek olarak, TeX'in yazdırılmasını sağlamak için tanımlayabilir \def\sayhello#1{Hello, #1!}
ve yazabilirsiniz . Buna “sınırsız makro” denir ve onu ilk (ve sadece bu durumda) parametresiyle beslemek için onu parantez içine alırsınız. Makro argümanı kaptığında TeX bu parantezleri kaldırır. 9 parametreye kadar kullanabilirsiniz: o zaman .\sayhello{Code Golfists}
Hello, Code Golfists!
\def\say#1#2{#1, #2!}
\say{Good news}{everyone}
Undelimited makro muadili, tahmin edileceği üzere, olanları sınırlandırılır :) Bir önceki tanım biraz daha yapabiliriz anlamsal : \def\say #1 to #2.{#1, #2!}
. Bu durumda, parametreleri parametre metni olarak adlandırılır . Bu tür parametre metni, makro argümanını #1
sınırlandırır ( ␣to␣
boşluklarla #2
ayrılmış ve sınırlandırılan .
). Bu tanımdan sonra \say Good news to everyone.
genişleyeceğiniz yazı yazabilirsiniz Good news, everyone!
. Güzel değil mi? :) Bununla birlikte, sınırlandırılmış bir argüman ( TeXbook'tan alıntı yaparak ) “ {...}
girdi içinde parametre olmayan bu belirteçlerin listesi tarafından takip edilen düzgün şekilde iç içe geçmiş gruplara sahip belirteçlerin en kısa (muhtemelen boş) sırası” dır . Bu genişlemesi anlamına gelir\say Let's go to the mall to Martin
garip bir cümle üretecek. Bu durumda siz “postu” ilk gerekiyordu ␣to␣
ile {...}
: \say {Let's go to the mall} to Martin
.
Çok uzak çok iyi. Şimdi işler garipleşmeye başladı. TeX bir karakter okuduğunda (bir “karakter kodu” ile tanımlanır), o karaktere ne anlama geleceğini tanımlayan bir karaktere “kategori kodu” (catcode, arkadaşlar için :) atar. Bu karakter ve kategori kodu kombinasyonu bir belirteç yapar ( örneğin , burada daha fazlası ). Bizim için burada ilgilenenler temelde:
Bir kontrol sekansı (bir makro için lüks bir isim) oluşturabilen jetonları tanımlayan catcode 11 . Varsayılan olarak tüm harfler [a-zA-Z] catcode 11'dir, dolayısıyla \hello
tek bir kontrol dizisi olan yazabilirim , \he11o
kontrol dizisini \he
iki karakter 1
takip eder, ardından harf izler o
, çünkü 1
catcode 11 değildir. yaptığı \catcode`1=11
bu noktadan sonra, \he11o
bir kontrol dizisi olacaktır. Önemli bir nokta catcodes TeX ilk elden karakterini gördüğünde ayarlanır ve bu tür catcode olduğunu olmasıdır donmuş ... SONSUZA DEK! (şartlar ve koşullar geçerli olabilir)
0"!@*(?,.-+/
ve benzeri diğer karakterlerin çoğu olan catcode 12 . Sadece kağıda yazı yazmak için kullandıkları en az özel tipte kodlardır. Ama hey, kim TeX'i yazmak için kullanıyor? (yine şartlar ve koşullar geçerli olabilir)
cehennem olan catcode 13 , :) Gerçekten. Okumayı bırak ve git hayatından bir şeyler yap. Catcode 13'ün ne olduğunu bilmek istemezsin. Hiç 13, Cuma duydum mu? İsmini nereden aldığını tahmin et! Devam etmek kendi sorumluluğunuzdadır! “Aktif” bir karakter olarak da adlandırılan bir kod 13 karakter artık sadece bir karakter değil, aynı zamanda bir makro! Parametrelere sahip olduğunu ve yukarıda gördüğümüz gibi genişleyeceğini tanımlayabilirsiniz. Bunu yaptıktan sonra \catcode`e=13
sen düşünmek yapabileceğiniz \def e{I am the letter e!}
ANCAK. SEN. YAPAMAM! e
artık bir mektup değil, o yüzden biliyorsun \def
değil \def
, öyle \d e f
! Oh, söylediğin başka bir mektup mu seçtin? Tamam! \catcode`R=13 \def R{I am an ARRR!}
. Çok iyi, Jimmy, dene! Bunu yapmaya ve R
kodunu girmeye cesaret edeceğim ! 13 kodlu kod budur. SAKİNİM! Hadi devam edelim.
Tamam, şimdi gruplaşmaya. Bu oldukça basittir. Bir grupta yapılan her ödev ( \def
bir ödev işlemidir \let
(içine gireceğiz) başka bir oyundur), bir grupta yapılanlar, bu ödev genel olmadığı sürece, söz konusu grubun başlamasından önceki haline geri yüklenir. Grupları başlatmanın birkaç yolu vardır, bunlardan biri 1 ve 2 karakterli kodludur (oh, tekrar kod kodlu). Varsayılan {
olarak catcode 1 veya başlangıç grubu ve }
catcode 2 veya son gruptur. Bir örnek: \def\a{1} \a{\def\a{2} \a} \a
Bu yazdırır 1 2 1
. Dış grup \a
oldu 1
o üzere yeniden tanımlandı sonra içeride, 2
ve grup bittiğinde, bu iade edildi 1
.
\let
Operasyon başka atama gibi operasyon \def
, daha çok farklı. İle \def
sen tanımlamak ile şeyler genişleyecektir makrolar \let
zaten var olan şeylerin kopyalarını oluşturmak. Sonra \let\blub=\def
( =
isteğe bağlıdır), e
örneğin başlangıcını yukarıdaki catcode 13 öğesinden değiştirebilir \blub e{...
ve bununla eğlenebilirsiniz. Ya da daha yerine yapabilirsiniz şeyler kırma düzeltmek (şuna bakar ederim!) R
Örnek: \let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}
. Hızlı soru: adını değiştirebilir misiniz \newR
?
Sonunda, sözde "sahte alanlar". Bu biraz tabu bir konudur, çünkü TeX - LaTeX Yığın Borsasında kazanılan ünün “sahte alan” sorularına cevap vererek kazandığı şöhretin göz ardı edilmemesi gerektiğini iddia ederken, diğerleri gönülden katılmıyorum. Kime katılıyorsun? Bahislerinizi yerleştirin! Bu arada: TeX satır sonunu bir boşluk olarak anlıyor. Aralarında bir satır sonu ( boş bir satır değil) bulunan birkaç sözcük yazmaya çalışın . Şimdi %
bu satırların sonuna bir tane ekleyin . Bu satır sonu alanlarını "yorumluyor" gibisin. Bu kadar :)
(Sırala) kodu çözme
Bu dikdörtgeni (tartışmalı) takip etmesi daha kolay bir şey haline getirelim:
{
\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 }
}
Her adımın açıklaması
Her satır bir tek komut içerir. Tek tek gidelim, onları parçalara ayırarak:
{
İlk önce bazı değişiklikleri (yani catcode değişiklikleri) yerel tutmak için bir grup başlatırız, böylece giriş metnini karıştırmazlar.
\let~\catcode
Temel olarak tüm TeX gizleme kodları bu talimatla başlar. Varsayılan olarak, hem düz TeX hem de LaTeX'te, ~
karakter ileride kullanılmak üzere bir makro haline getirilebilen bir aktif karakterdir. Ve TeX kodunu garipleştirmek için en iyi araç catcode değişiklikleridir, bu nedenle bu genellikle en iyi seçimdir. Şimdi \catcode`A=13
biz yerine ~`A13
( =
isteğe bağlı) yazabiliriz :
~`A13
Şimdi mektup A
aktif bir karakter ve bir şey yapması için tanımlayabiliriz:
\defA#1{~`#113\gdef}
A
şimdi bir argüman alan bir makro (başka bir karakter olmalı). İlk Tartışmanın catcode aktif hale getirmek için 13 olarak değiştirilir: ~`#113
(replace ~
tarafından \catcode
ve bir ekleme =
ve varsa: \catcode`#1=13
). Sonunda giriş akışında bir \gdef
(global \def
) bırakır . Kısacası, A
başka bir karakteri aktif hale getirir ve tanımına başlar. Hadi deneyelim:
AGG#1{~`#113\global\let}
AG
ilk önce “aktive eder” G
ve yapar \gdef
, ardından bir sonraki G
tanımlamaya başlar. Tanımı G
bu çok benzer A
bir yerine o hariç \gdef
bir does \global\let
(bir yok \glet
gibi \gdef
). Kısacası, G
bir karakteri aktive eder ve onu başka bir şey yapar. Daha sonra kullanacağımız iki komut için kısayollar yapalım:
GFF\else
GHH\fi
Şimdi yerine \else
ve \fi
basitçe F
ve kullanabilirsiniz H
. Çok daha kısa :)
AQQ{Q}
Şimdi A
başka bir makro tanımlamak için tekrar kullanıyoruz Q
. Yukarıdaki ifade temel olarak (daha az karışık bir dilde) yapar \def\Q{\Q}
. Bu çok ilginç bir tanım değil, ama ilginç bir özelliğe sahip. Kodun bir kısmı, hiç genişlediğinde sadece makro kırmak istiyoruz sürece Q
olan Q
benzersiz bir işareti gibi davranır böylece, kendisi (bir deniyor kuark ). \ifx
Bir makronun argümanının aşağıdaki gibi kuark olup olmadığını test etmek için koşullu kullanabilirsiniz \ifx Q#1
:
AII{\ifxQ}
Böylece böyle bir işaretleyici bulduğuna emin olabilirsin. Bu tanımda \ifx
ve arasındaki boşluğu kaldırdığımı fark et Q
. Genellikle bu bir hataya yol açar (sözdiziminin vurgulamasının \ifxQ
bir şey olduğunu düşündüğünü unutmayın ), ancak şimdi Q
catcode 13 olduğundan , bir kontrol dizisi oluşturamaz. Ancak, bu kuark genişlemesini ya da çünkü sonsuz döngüye takılıp alırsınız değil, dikkatli olun Q
genişleyeceği için Q
hangi genişler Q
hangi ...
Şimdi ön hazırlıklar yapıldıktan sonra, setterl için uygun algoritmaya gidebiliriz. TeX'in belirteçlenmesi nedeniyle algoritmanın geriye doğru yazılması gerekir. Bunun nedeni bir tanım yaptığınız zaman TeX'in geçerli ayarları kullanarak tanımdaki karakterlere belirteç vermesi (katod atama), örneğin, eğer:
\def\one{E}
\catcode`E=13\def E{1}
\one E
çıktı ise E1
, tanımların sırasını değiştirirsem:
\catcode`E=13\def E{1}
\def\one{E}
\one E
çıktı 11
. Bunun nedeni, ilk örnekte E
tanımdaki tanımın, kod değişikliği yapılmadan önce bir harf (kod kodu 11) olarak belirtilmiş olmasıdır, bu yüzden her zaman bir harf olacaktır E
. Bununla birlikte, ikinci örnekte, E
ilk önce aktif hale getirildi ve ancak daha sonra \one
tanımlandı ve şimdi tanım, E
genişleyen catcode 13'ü içeriyor 1
.
Bununla birlikte, bu gerçeği görmezden geleceğim ve tanımları mantıklı (ancak çalışmayan) bir düzen için yeniden sıralayacağım. Aşağıdaki paragraflarda size harfler varsayabiliriz B
, C
, D
ve E
aktiftirler.
\gdef\S#1{\iftrueBH#1 Q }
(önceki sürümde küçük bir hata olduğunu fark edin, yukarıdaki tanımdaki son boşluğu içermiyordu. Sadece bunu yazarken fark ettim. Okumaya devam edin ve neden makroyu düzgün bir şekilde sonlandırmak için buna ihtiyacımız olduğunu göreceksiniz. )
Öncelikle, kullanıcı düzeyinde makro tanımlamak \S
. Bu, dostça (?) Bir sözdizimine sahip aktif bir karakter olmamalıdır, bu yüzden gwappins eht setterl için makro böyledir \S
. Makro, her zaman gerçek bir koşullu ile başlar \iftrue
(kısa sürede neden belli olur) ve ardından eşleşmesi için B
makroyu H
(daha önce tanımladığımız \fi
) çağırır \iftrue
. Sonra makro argümanını izleriz, #1
ardından boşluk ve kuark izleriz Q
. Varsayalım \S{hello world}
, sonra girdi akışını kullanın.Şuna bakmalıyım: \iftrue BHhello world Q␣
(Son boşluğu değiştirdim, ␣
böylece sitenin görüntülenmesi onu kodun önceki sürümünde yaptığım gibi yemez). \iftrue
doğrudur, bu yüzden genişler ve biz geride kalırız BHhello world Q␣
. TeX yok değil kaldırmak \fi
( H
) şartlı değerlendirilir sonrasına kadar, bunun yerine orada bırakır \fi
edilir aslında genişletilmiş. Şimdi B
makro genişletildi:
ABBH#1 {HI#1FC#1|BH}
B
Bir olan sınırlandırılmış makro kimin parametre metindir H#1␣
argüman arasındaki neyse yani, H
ve bir boşluk. Genişlemesine önce giriş akışı Yukarıdaki örnekten devam B
IS BHhello world Q␣
. B
izlemektedir H
bu (aksi Tex bir hata artıracaktır) gerektiği gibi, daha sonra bir sonraki alan arasında hello
ve world
bu yüzden, #1
bir kelime hello
. Ve burada giriş metnini boşluklarda bölmeliyiz. Yay: D genişlemesi B
ile, giriş akımı ve yerine geçer, birinci boşluğa kaldırır her up HI#1FC#1|BH
ile #1
olmak hello
: HIhelloFChello|BHworld Q␣
. BH
Kuyruk özyinelemesini yapmak için giriş akımında daha sonra yeni olduğuna dikkat edin .B
ve sonraki kelimeleri işler. Bu kelime işlendikten sonra B
, bir sonraki kelimeyi işlenecek kelime kuark olana kadar işler Q
. Q
Sınırlandırılmış makro , argümanın sonunda bir tane B
gerektirdiğinden sonraki son boşluğa ihtiyaç vardır . Önceki sürümde (düzenleme geçmişine bakın), eğer kullanırsanız kod yanlış davranır \S{hello world}abc abc
( abc
s arasındaki boşluk kaybolur).
Tamam, giriş akımına geri: HIhelloFChello|BHworld Q␣
. İlk önce başlangıcı tamamlayan H
( \fi
) var \iftrue
. Şimdi bizde var (sözde kodlanmış):
I
hello
F
Chello|B
H
world Q␣
I...F...H
Düşünce aslında bir olduğunu \ifx Q...\else...\fi
yapısı. \ifx
Kelime (ilk belirteç) halinde alıp test eder olan Q
kuark. Eğer öyleyse yapması gereken şey ve icra sonlandığı olduğunu kalır aksi ne var: Chello|BHworld Q␣
. Şimdi C
genişletildi:
ACC#1#2|{D#2Q|#1 }
Birinci bağımsız değişkeni C
tek bir belirteci olacak çaprazlı çok sürece undelimited olup, ikinci bağımsız tarafından sınırlanan |
bu nedenle genişlemesi sonra, C
(ile #1=h
ve #2=ello
giriş akımı olması durumunda): DelloQ|h BHworld Q␣
. Bildirim başka o |
orada konur ve h
içinde hello
bundan sonra konur. Değişimin yarısı yapılır; ilk harf sonunda. TeX'te, bir belirteç listesinin ilk belirtecini almak kolaydır. Basit bir makro \def\first#1#2|{#1}
, kullandığınızda ilk harfi alır \first hello|
. Sonuncusu bir sorundur çünkü TeX her zaman “en küçük, muhtemelen boş” simge listesini argüman olarak alır, bu yüzden birkaç çalışmaya ihtiyacımız var. Belirteç listesindeki bir sonraki öğe D
:
ADD#1#2|{I#1FE{}#1#2|H}
Bu D
makro çevreleyenlerden biridir ve kelimenin tek bir harf olduğu tek durumda yararlıdır. Diyelim ki hello
biz yerine x
. Bu durumda, giriş akışı olur DQ|x
, daha sonra D
(ile genişler #1=Q
ve #2
hiç boş): IQFE{}Q|Hx
. Bu, argümanın kuark olduğunu görecek ve içerisindeki yalnızca dizgi için ayrılan yürütmeyi kesecek olan I...F...H
( \ifx Q...\else...\fi
) bloğuna benzer . (Dönen Diğer durumlarda örneğin), (ile artıracağı ve için): . Yine, kontrol eder ama başarısız ve alacak dalı: . Şimdi bu şeyin son parçası,B
x
hello
D
#1=e
#2=lloQ
IeFE{}elloQ|Hh BHworld Q␣
I...F...H
Q
\else
E{}elloQ|Hh BHworld Q␣
E
makro genişler:
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
Buradaki parametre metni oldukça benzer C
ve D
; birinci ve ikinci argümanlar reddedilir ve sonuncusu tarafından sınırlandırılır |
. Bu gibi giriş akışı görünüm: E{}elloQ|Hh BHworld Q␣
daha sonra E
genişler ile ( #1
boş #2=e
ve #3=lloQ
): IlloQeFE{e}lloQ|HHh BHworld Q␣
. Başka bir I...F...H
kuark blok kontrol (ki görür l
ve döner false
) E{e}lloQ|HHh BHworld Q␣
. Şimdi E
(yine genişler #1=e
boş, #2=l
ve #3=loQ
): IloQleFE{el}loQ|HHHh BHworld Q␣
. Ve tekrar I...F...H
. Makro, Q
bulunana ve true
dal alınana kadar birkaç yineleme daha yapar : E{el}loQ|HHHh BHworld Q␣
-> IoQlelFE{ell}oQ|HHHHh BHworld Q␣
-> E{ell}oQ|HHHHh BHworld Q␣
-> IQoellFE{ello}Q|HHHHHh BHworld Q␣
. Şimdi kuark bulundu ve şartlı genişletildiği etmektir: oellHHHHh BHworld Q␣
. Uf.
Bekle, bunlar nedir? NORMAL MEKTUPLAR? Ah oğlum! Harfler nihayet bulunurlar ve TeX aşağı yazıyor oell
sonra bir grup, H
( \fi
) bulundu ve ile giriş akışı bırakarak (hiçbir şey) genişletilir: oellh BHworld Q␣
. Şimdi ilk kelimenin ilk ve son harfleri değiştirildi ve TeX'in bir sonraki bulduğu şey B
, bir sonraki kelimenin tüm işlemini tekrarlamak için diğeri .
}
Sonunda gruba geri döndük, böylece tüm yerel görevlerin yerine getirilebilmesi sağlandı. Yerel atamaları harflerin catcode değişikliklerdir A
, B
, C
, ... makro yapıldığı yüzden normal harf anlam dönmek olduğunu ve güvenli metinde kullanılabilir. Ve bu kadar. Şimdi \S
orada tanımlanan makro, metnin yukarıdaki gibi işlenmesini tetikleyecektir.
Bu kodla ilgili ilginç bir şey, tamamen genişletilebilir olmasıdır. Başka bir deyişle, patlayacaklarından endişe etmeden, değişkenleri argümanlarda güvenle kullanabilirsiniz. Bir \if
testteki bir kelimenin son harfinin, ikinci harf ile aynı olup olmadığını (hangi sebepten olursa olsun) kontrol etmek için bile kodu kullanabilirsiniz :
\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
(Muhtemelen de) wordy açıklama için üzgünüm. Ben de TeXies olmayanlar için mümkün olduğunca net yapmaya çalıştım :)
Sabırsız için özeti
Makro \S
, girdiyi B
son bir boşlukla sınırlandırılmış belirteçlerin listelerini alan ve bunları ileten aktif bir karakterle hazırlar C
. C
o listedeki ilk simgeyi alır ve onu simgeli listenin sonuna taşır ve D
kalanlarla genişler . D
“kalanların” boş olup olmadığını kontrol eder, bu durumda tek harfli bir kelime bulunursa hiçbir şey yapmaz; aksi takdirde genişler E
. E
kelime listesindeki son harfi bulana kadar belirteç listesinde dolaşır, bulunduğunda bu son harfi terk eder, ardından kelimenin ortasını izler, sonra bunu token akışının sonunda bırakılan ilk harf izler. C
.
Hello, world!
olur,elloH !orldw
(noktalama işaretini bir harf olarak değiştirmek) veyaoellH, dorlw!
(noktalama işaretini yerinde tutmak)?