T-SQL, 1974 - 50 = 1924 ไบต์
ฉันรู้ว่าการเล่นกอล์ฟใน SQL นั้นเทียบเท่ากับการเล่น 18 หลุมโดยไม่มีอะไรเลยนอกจากลิ่มทราย แต่ฉันได้ลองท้าทายสิ่งนี้และฉันคิดว่าฉันสามารถทำสิ่งที่น่าสนใจได้หลายวิธี
สิ่งนี้จะสนับสนุน vinculum สำหรับทั้งอินพุตและเอาต์พุต ฉันยอมรับการประชุมโดยใช้เครื่องหมายตัวหนอนเพื่อเป็นตัวแทนดังนั้น V ~ คือ 5,000, X ~ คือ 10,000 เป็นต้นและควรจัดการเอาต์พุตได้สูงถึง 399,999 ตามการใช้ตัวเลขโรมันแบบมาตรฐาน หลังจากนั้นจะทำการเข้ารหัสแบบโรมันที่ไม่ได้มาตรฐานบางส่วนของสิ่งใดก็ตามในช่วงที่ได้รับการสนับสนุนของ INT
เนื่องจากเป็นเลขจำนวนเต็มทั้งหมดผลลัพธ์ที่ไม่เป็นจำนวนเต็มจะถูกปัดเศษโดยปริยาย
DECLARE @i VARCHAR(MAX)
SET @i='I+V*IV+IX*MXLVII+X~C~DCCVI'
SELECT @i
DECLARE @t TABLE(i INT IDENTITY,n VARCHAR(4),v INT)
DECLARE @u TABLE(n VARCHAR(50),v INT)
DECLARE @o TABLE(n INT IDENTITY,v CHAR(1))
DECLARE @r TABLE(n INT IDENTITY,v INT,r VARCHAR(MAX))
DECLARE @s TABLE(v INT,s VARCHAR(MAX))
DECLARE @p INT,@x VARCHAR(4000)='SELECT ',@j INT=1,@m INT,@y INT,@z VARCHAR(2),@q VARCHAR(50)='+-/*~]%'
INSERT @t(n,v) VALUES('i',1),('iv',4),('v',5),('ix',9),('x',10),('xl',50),('l',50),('xc',90),('c',100),('cd',400),('d',500),('cm',900),('m',1000),('mv~',4000),('v~',5000),('mx~',9000),('x~',10000),('x~l~',40000),('l~',50000),('x~c~',90000),('c~',100000)
INSERT @u VALUES('%i[^i'+@q,-2),('%v[^vi'+@q,-10),('%x[^xvi'+@q,-20),('%l[^lxvi'+@q,-100),('%c[^clxvi'+@q,-200),('%d[^dclxvi'+@q,-1000),('%mx~%',-2010),('%x~l~%',-20060),('%x~c~%',-20110)
WHILE PATINDEX('%[+-/*]%', @i)!=0
BEGIN
SET @p=PATINDEX('%[+-/*]%', @i)
INSERT @o(v) SELECT SUBSTRING(@i,@p,1)
INSERT @r(r) SELECT SUBSTRING(@i,1,@p-1)
SET @i=STUFF(@i,1,@p,'')
END
INSERT @r(r) SELECT @i
UPDATE r SET v=COALESCE(q.v,0) FROM @r r LEFT JOIN (SELECT r.r,SUM(u.v)v FROM @u u JOIN @r r ON r.r LIKE u.n GROUP BY r.r)q ON q.r=r.r
UPDATE r SET v=r.v+q.v FROM @r r JOIN (SELECT r.n,r.r,SUM((LEN(r.r)-LEN(REPLACE(r.r,t.n,REPLICATE(' ',LEN(t.n)-1))))*t.v) v FROM @r r JOIN @t t ON CHARINDEX(t.n,r.r) != 0 AND (LEN(t.n)=1 OR (LEN(t.n)=2 AND RIGHT(t.n,1)='~')) GROUP BY r.n,r.r) q ON q.r=r.r AND q.n = r.n
SELECT @m=MAX(n) FROM @o
SELECT @x=@x+REPLICATE('(',@m)+CAST(v AS VARCHAR) FROM @r WHERE n=1
WHILE @j<=@m
BEGIN
SELECT @x=@x+o.v+CAST(r.v AS VARCHAR)+')'
FROM @o o JOIN @r r ON r.n=o.n+1 WHERE o.n=@j
SET @j=@j+1
END
INSERT @s(v,s) EXEC(@x+',''''')
UPDATE @s SET s=s+CAST(v AS VARCHAR(MAX))+' = '
SET @j=21
WHILE @j>0
BEGIN
SELECT @y=v,@z=n FROM @t WHERE i = @j
WHILE @y<=(SELECT v FROM @s)
BEGIN
UPDATE @s SET v=v-@y,s=s+@z
END
SET @j=@j-1
END
SELECT @x+' = '+UPPER(s) FROM @s
ฉันยังคงแก้ปัญหาด้วย set-based solution เพื่อแทนที่การวนลูปบางอันที่อาจลดจำนวนไบต์ลงและเป็นตัวอย่างที่ดีกว่าของ SQL ที่ใช้สำนวน นอกจากนี้ยังมีบางไบต์ที่จะได้รับโดยการลดการใช้นามแฝงของตารางให้น้อยที่สุด แต่เนื่องจากภาษานี้ไม่สามารถเอาชนะได้ฉันจึงมาที่นี่เพื่อแสดงชุด Don Quixote ของฉัน :)
SELECT @i ที่ด้านบนป้อนข้อมูลซ้ำ:
I+V*IV+IX*MXLVII+X~C~DCCVI
และ SELECT เมื่อสิ้นสุดจะส่งคืน:
SELECT (((((1+5)*4)+9)*1047)+90706) = 125257 = C~X~X~V~CCLVII
และคุณสามารถทดสอบด้วยตัวเองได้ที่SQLFiddle นี้
และฉันจะกลับไปเพิ่มความเห็นเกี่ยวกับวิธีการทำงานเพราะเหตุใดจึงโพสต์คำตอบที่หายไปอย่างเห็นได้ชัดถ้าคุณไม่ใช้ประโยชน์จากคุณค่าทางการศึกษา?