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 }}
ลองออนไลน์! (Overleaf ไม่แน่ใจว่ามันทำงานอย่างไร)
ไฟล์ทดสอบเต็มรูปแบบ:
{\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}
คู่ของแมโคร undelimited จะแปลกใจคนคั่น :) คุณสามารถทำให้คำนิยามก่อนหน้าตาดเพิ่มเติมsemantical\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 สำหรับเพื่อน ๆ :) ซึ่งจะกำหนดความหมายของตัวละครนั้น การรวมกันของตัวละครและรหัสหมวดหมู่นี้ทำให้โทเค็น (ตัวอย่างเพิ่มเติมที่นี่ ) คนที่น่าสนใจสำหรับเราที่นี่เป็นพื้น:
catcode 11ซึ่งกำหนดโทเค็นซึ่งสามารถสร้างลำดับการควบคุม (ชื่อ posh สำหรับแมโคร) โดยค่าเริ่มต้นตัวอักษรทั้งหมด [a-zA-Z] เป็น catcode 11 ดังนั้นฉันสามารถเขียน\hello
ซึ่งเป็นหนึ่งในลำดับการควบคุมเดียวในขณะ\he11o
ที่ลำดับการควบคุม\he
ตามด้วยอักขระสองตัว1
ตามด้วยตัวอักษรo
เพราะ1
ไม่ใช่ catcode 11 ถ้าฉัน ได้\catcode`1=11
จากจุด\he11o
นั้นไปเป็นลำดับการควบคุมหนึ่ง สิ่งหนึ่งที่สำคัญคือการที่มีการตั้งค่า catcodes เมื่อเท็กซ์แรกที่เห็นตัวละครที่อยู่ในมือและ catcode ดังกล่าวเป็นแช่แข็ง ... ตลอดไป! (ข้อกำหนดและเงื่อนไขอาจนำมาใช้)
catcode 12ซึ่งเป็นอักขระส่วนใหญ่เช่น0"!@*(?,.-+/
และอื่น ๆ พวกมันเป็นประเภท catcode พิเศษที่น้อยที่สุดเพราะมันทำหน้าที่สำหรับการเขียนเนื้อหาบนกระดาษเท่านั้น แต่เดี๋ยวก่อนใครใช้ TeX ในการเขียน?!? (อาจมีข้อกำหนดและเงื่อนไขอีกครั้ง)
catcode 13ซึ่งเป็นนรก :) จริง ๆ หยุดอ่านและไปทำอะไรบางอย่างในชีวิตของคุณ คุณไม่ต้องการที่จะรู้ว่า catcode 13 คืออะไร เคยได้ยินวันศุกร์ที่ 13 ไหม ลองเดาดูว่ามันได้ชื่อมาจากไหน! ดำเนินการต่อด้วยความเสี่ยงของคุณเอง! catcode 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
ในรหัสของคุณ! นั่นคือสิ่งที่ catcode 13 เป็น ฉันใจเย็น! ไปกันเถอะ
โอเคตอนนี้เพื่อจัดกลุ่ม ค่อนข้างตรงไปตรงมา สิ่งที่ได้รับมอบหมาย ( \def
เป็นการดำเนินการที่ได้รับมอบหมาย\let
(เราจะเข้าสู่มัน) เป็นอีกสิ่งหนึ่ง) ที่ทำในกลุ่มจะถูกเรียกคืนเป็นสิ่งที่พวกเขาเคยทำก่อนที่กลุ่มนั้นจะเริ่มต้นเว้นแต่ว่าการมอบหมายนั้นจะเป็นระดับโลก มีหลายวิธีในการเริ่มกลุ่มโดยหนึ่งในนั้นคือ catcode 1 และ 2 ตัวอักษร (โอ้ catcodes อีกครั้ง) โดยค่าเริ่มต้น{
คือ catcode 1 หรือกลุ่มเริ่มต้นและ}
เป็น catcode 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
ตัวอย่างจากรายการ catcode 13 ด้านบนเป็น\blub e{...
และสนุกกับสิ่งนั้น หรือดีกว่าแทนการทำลายสิ่งที่คุณสามารถแก้ไข (คุณจะดูที่!) ด้วยเช่น:R
\let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}
คำถามด่วน: คุณสามารถเปลี่ยนชื่อเป็น\newR
?
ในที่สุดสิ่งที่เรียกว่า "ช่องว่างปลอม" นี่เป็นหัวข้อที่ต้องห้ามเพราะมีคนที่อ้างว่าชื่อเสียงที่ได้รับจากTeX - LaTeX Stack Exchangeโดยการตอบคำถาม "ช่องว่างปลอม" ไม่ควรได้รับการพิจารณาในขณะที่คนอื่นไม่เห็นด้วยอย่างสุดใจ คุณเห็นด้วยกับใคร วางเดิมพันของคุณ! ในขณะเดียวกัน: TeX เข้าใจการแตกบรรทัดเป็นพื้นที่ ลองเขียนหลาย ๆ คำโดยใช้ตัวแบ่งบรรทัด (ไม่ใช่บรรทัดว่าง ) ระหว่างคำเหล่านั้น ตอนนี้เพิ่ม a %
ท้ายบรรทัดเหล่านี้ มันเหมือนกับว่าคุณกำลัง“ คอมเม้นท์” จุดสิ้นสุดของบรรทัดเหล่านี้ แค่นั้นแหละ :)
(เรียงจาก) ถอดรหัสออก
ให้สี่เหลี่ยมผืนผ้านั้นเป็นสิ่งที่ง่ายขึ้น (ตามเนื้อหา):
{
\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 }
}
คำอธิบายของแต่ละขั้นตอน
แต่ละบรรทัดมีหนึ่งคำสั่งเดียว ไปทีละคนแล้วผ่าพวกเขา:
{
ก่อนอื่นเราเริ่มกลุ่มเพื่อให้การเปลี่ยนแปลงบางอย่าง (เช่นการเปลี่ยนแปลง catcode) อยู่ในเครื่องเพื่อไม่ให้สับสนกับข้อความที่ป้อนเข้า
\let~\catcode
โดยทั่วไปทุกรหัสเท็กซ์ obfuscation เริ่มต้นด้วยการเรียนการสอนนี้ โดยค่าเริ่มต้นทั้งใน TeX ธรรมดาและ LaTeX ~
ตัวละครเป็นตัวละครที่ใช้งานหนึ่งตัวซึ่งสามารถทำเป็นแมโครเพื่อใช้งานต่อไป และเครื่องมือที่ดีที่สุดสำหรับ weirdifying รหัส TeX คือการเปลี่ยนแปลง catcode ดังนั้นโดยทั่วไปนี่เป็นตัวเลือกที่ดีที่สุด ตอนนี้แทนที่จะ\catcode`A=13
เราสามารถเขียน~`A13
( =
เป็นตัวเลือก):
~`A13
ตอนนี้ตัวอักษรA
เป็นตัวละครที่ใช้งานอยู่และเราสามารถกำหนดให้ทำอะไรบางอย่าง:
\defA#1{~`#113\gdef}
A
เป็นแมโครที่รับอาร์กิวเมนต์หนึ่งตัว (ซึ่งควรเป็นอักขระอื่น) แรก catcode ของการโต้แย้งที่มีการเปลี่ยนแปลงถึง 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
catcode 13 ไม่สามารถสร้างลำดับการควบคุมได้ ระวัง แต่ไม่ได้ที่จะขยายควาร์กนี้หรือคุณจะได้รับการติดอยู่ในวง จำกัด เพราะQ
การขยายตัวในการQ
ที่จะขยายQ
ซึ่ง ...
ตอนนี้การแข่งขันรอบแรกเสร็จสิ้นแล้วเราสามารถไปยังอัลกอริทึมที่เหมาะสมกับ pwas eht setterl เนื่องจากโทเค็นของ TeX จะต้องเขียนอัลกอริทึมไปข้างหลัง นี่เป็นเพราะในเวลาที่คุณทำการกำหนด TeX จะทำเครื่องหมาย (กำหนด catcodes) ให้กับตัวละครในการกำหนดโดยใช้การตั้งค่าปัจจุบันดังนั้นตัวอย่างเช่นถ้าฉันทำ:
\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
คำนิยามในโทเค็นเป็นตัวอักษร (catcode 11) ก่อนที่ catcode จะเปลี่ยนดังนั้นมันจะเป็นตัวอักษรE
เสมอ ในตัวอย่างที่สอง แต่E
เป็นครั้งแรกที่ใช้งานและเพียงแล้ว\one
ถูกกำหนดและตอนนี้ความหมายมี catcode 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
และเว้นวรรค อย่างต่อเนื่องตัวอย่างข้างต้นสตรีมใส่ก่อนที่จะมีการขยายตัวของมีB
ตามด้วยตามที่ควร (มิฉะนั้นเท็กซ์จะยกข้อผิดพลาด) แล้วพื้นที่ต่อไปคือระหว่างและเพื่อให้เป็นคำว่า และที่นี่เราต้องแยกข้อความอินพุตที่ช่องว่าง ยาย: D การขยายตัวของเอาทุกอย่างขึ้นอยู่กับพื้นที่เป็นครั้งแรกจากสตรีมใส่และแทนที่โดยมีเป็น: โปรดสังเกตว่ามีใหม่ในสตรีมอินพุตในภายหลังเพื่อทำการวนรอบแบบซ้ำBHhello world Q␣
B
H
hello
world
#1
hello
B
HI#1FC#1|BH
#1
hello
HIhelloFChello|BHworld Q␣
BH
B
และประมวลผลคำภายหลัง หลังจากคำนี้มีการประมวลผลกระบวนการคำถัดไปจนกว่าจะมีคำพูดเพื่อจะประมวลผลเป็นควาร์กB
Q
ต้องการพื้นที่สุดท้ายหลังQ
เนื่องจากแมโครที่B
มีการคั่นต้องการหนึ่งที่ท้ายอาร์กิวเมนต์ ด้วยเวอร์ชันก่อนหน้า (ดูประวัติการแก้ไข) รหัสจะทำงานผิดปกติหากคุณใช้\S{hello world}abc abc
(ช่องว่างระหว่างabc
s จะหายไป)
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
เป็น undelimited ดังนั้นถ้ายันมันจะเป็นโทเค็นเดียวอาร์กิวเมนต์ที่สองจะถูกคั่นด้วย|
ดังนั้นหลังจากการขยายตัวของ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
; การขัดแย้งครั้งแรกและครั้งที่สองจะ undelimited |
และคนสุดท้ายที่ถูกคั่นด้วย กระแสการป้อนข้อมูลลักษณะเช่นนี้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␣
วุ้ย.
โอ้เดี๋ยวก่อนพวกนี้คืออะไร? ตัวอักษรปกติ? โอ้เด็ก! ตัวอักษรเป็นที่สุดพบและเท็กซ์เขียนลงoell
แล้วพวงของH
( \fi
) ที่พบและการขยายตัว (เพื่ออะไร) oellh BHworld Q␣
ออกจากสตรีมใส่ด้วย: ตอนนี้คำแรกมีตัวอักษรตัวแรกและตัวสุดท้ายสลับและสิ่งที่ TeX พบต่อไปคืออีกคำ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
prepends การป้อนข้อมูลด้วยตัวใช้งานที่คว้ารายการของสัญญาณที่คั่นด้วยช่องว่างสุดท้ายและผ่านพวกเขาไปB
ใช้โทเค็นแรกในรายการนั้นและย้ายไปยังจุดสิ้นสุดของรายการโทเค็นและขยายด้วยสิ่งที่เหลืออยู่ ตรวจสอบว่า“ สิ่งที่เหลืออยู่” นั้นว่างเปล่าหรือไม่ซึ่งในกรณีนี้จะพบคำตัวอักษรเดียวแล้วไม่ทำอะไรเลย มิฉะนั้นการขยายตัว วนรอบรายการโทเค็นจนกระทั่งพบตัวอักษรตัวสุดท้ายในคำเมื่อพบว่าออกจากตัวอักษรตัวสุดท้ายตามด้วยคำกลางซึ่งตามด้วยตัวอักษรตัวแรกที่เหลือในตอนท้ายของกระแสโทเค็นด้วย.C
C
D
D
E
E
C
Hello, world!
กลายเป็น,elloH !orldw
(การสลับเครื่องหมายวรรคตอนเป็นตัวอักษร) หรือoellH, dorlw!
(ใช้เครื่องหมายวรรคตอนแทน) หรือไม่