查看: 8103|回复: 24

[精华] 复活节最短编程之神秘代码版

[复制链接]
论坛徽章:
540
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
发表于 2011-5-6 00:51 | 显示全部楼层 |阅读模式
OO提出的思路,我把它实现了,正所谓君子动口,小人动手


CREATE OR REPLACE PACKAGE easter
AS
PROCEDURE showAllEasterDay;
PROCEDURE showMaxOccurenceEasterDay;
PROCEDURE showLeapEasterDay;
PROCEDURE showFoolEasterDay;
END;
/


DECLARE
  lv_sql CLOB;
  a VARCHAR2(2000);
  b VARCHAR2(2000);
  c VARCHAR2(2000);
  d VARCHAR2(2000);
  
  FUNCTION encode (p IN VARCHAR2) RETURN VARCHAR2
  AS
     lv_ret VARCHAR(32767);
     lv_asc NUMBER;
     s VARCHAR2(2000) := UPPER(REPLACE(p,CHR(10),' '));
  BEGIN
     FOR i IN 1..LENGTH(p) LOOP
         lv_asc := ASCII(SUBSTR(s,i,1));
         lv_ret := lv_ret||LPAD(' ',TRUNC(lv_asc/10)-1)||CHR(9)||LPAD(' ',MOD(lv_asc,10))||CHR(9);
     END LOOP;
     RETURN lv_ret;
  END encode;
BEGIN
  a := q'{
BEGIN
   DBMS_OUTPUT.PUT_LINE('YEAR     DAY');
   FOR I IN (
   SELECT (N+1900)||TO_CHAR(TO_DATE((N+1900)||'04','YYYYMM')+24-M-MOD(N+TRUNC(N/4)+31-M,7),'    MM-DD') S
     FROM (SELECT MOD(11*MOD(N,19)+4-TRUNC((7*MOD(N,19)+1)/19),29) M,N
             FROM (SELECT LEVEL+110 N FROM DUAL CONNECT BY LEVEL<=89)
           )
    ORDER BY 1
   ) LOOP
     DBMS_OUTPUT.PUT_LINE(I.S);
   END LOOP;
END;}';

  b := q'{
DECLARE
   S STRING(1000);
   S3 STRING(1000);
   S4 STRING(1000);
   C NUMBER;
   C3 NUMBER;
   C4 NUMBER;
BEGIN
   DBMS_OUTPUT.PUT_LINE('MAXOCC   MO_CNT        MAXOCC_3   MO3_CNT              MAXOCC_4          MO4_CNT');
   FOR I IN (
             WITH E AS (
             SELECT S
                   ,RANK() OVER(ORDER BY CNT DESC) R
                   ,RANK() OVER(ORDER BY CASE WHEN S LIKE'03%' THEN CNT ELSE -1 END DESC) R3
                   ,RANK() OVER(ORDER BY CASE WHEN S LIKE'04%' THEN CNT ELSE -1 END DESC) R4
                   ,CNT
                   ,CASE WHEN S LIKE'03%' THEN CNT ELSE -1 END
               FROM ( SELECT S,COUNT(*) CNT
                        FROM (SELECT TO_CHAR(TO_DATE((N+1900)||'04','YYYYMM')+24-M-MOD(N+TRUNC(N/4)+31-M,7),'MM-DD') S
                                FROM (SELECT MOD(11*MOD(N,19)+4-TRUNC((7*MOD(N,19)+1)/19),29) M,N
                                        FROM (SELECT LEVEL+110 N FROM DUAL CONNECT BY LEVEL<=89)
                                      )
                              )
                      GROUP BY S
                    )
             )
             SELECT * FROM E WHERE 1 IN (R,R3,R4) ORDER BY 1
   ) LOOP
      S:=S||CASE WHEN I.R=1 THEN ','||I.S END;
      S3:=S3||CASE WHEN I.R3=1 THEN ','||I.S END;
      S4:=S4||CASE WHEN I.R4=1 THEN ','||I.S END;
      C := CASE WHEN I.R=1 THEN I.CNT ELSE C END;
      C3:= CASE WHEN I.R3=1 THEN I.CNT ELSE C3 END;
      C4:= CASE WHEN I.R4=1 THEN I.CNT ELSE C4 END;
   END LOOP;
   DBMS_OUTPUT.PUT_LINE(SUBSTR(S,2)||' '||C||' '||SUBSTR(S3,2)||' '||C3||' '||SUBSTR(S4,2)||' '||C4);
END;}';
  
  c := q'{
BEGIN
   DBMS_OUTPUT.PUT_LINE('ABSENT_START      ABSENT_END');
   FOR l IN (
   SELECT MIN(d)||'     '||MAX(d) d
     FROM (SELECT TO_CHAR(DATE '1-3-21'+LEVEL,'MM-DD') d FROM DUAL CONNECT BY LEVEL<36
           MINUS
           SELECT TO_CHAR(TO_DATE((N+1900)||'04','YYYYMM')+24-M-MOD(N+TRUNC(N/4)+31-M,7),'MM-DD') S
            FROM (SELECT MOD(11*MOD(N,19)+4-TRUNC((7*MOD(N,19)+1)/19),29) M,N
                    FROM (SELECT LEVEL+110 N FROM DUAL CONNECT BY LEVEL<=89)
                  )
           ORDER BY 1
           )
   GROUP BY TO_DATE(d,'MM-DD')-ROWNUM
   ) LOOP
      DBMS_OUTPUT.PUT_LINE(l.d);
   END LOOP;
END;
}';

  d := q'{
BEGIN
   DBMS_OUTPUT.PUT_LINE('YEAR        TOTAL');
   FOR l IN (
       SELECT SUBSTR(s,1,4)||'         '||COUNT(*) OVER() s
         FROM (
               SELECT (N+1900)||TO_CHAR(TO_DATE((N+1900)||'04','YYYYMM')+24-M-MOD(N+TRUNC(N/4)+31-M,7),'    MM-DD') S
                 FROM (SELECT MOD(11*MOD(N,19)+4-TRUNC((7*MOD(N,19)+1)/19),29) M,N
                         FROM (SELECT LEVEL+110 N FROM DUAL CONNECT BY LEVEL<=89)
                       )
              )
         WHERE SUBSTR(s,9) ='04-01'
   ) LOOP
      DBMS_OUTPUT.PUT_LINE(l.s);
   END LOOP;
END;}';
  
  lv_sql := '
CREATE OR REPLACE PACKAGE BODY easter
AS
   SUBTYPE t IS STRING(32000);
   a t := '''||encode(a)||''';
   b t := '''||encode(b)||''';
   c t := '''||encode(c)||''';
   d t := '''||encode(d)||''';
  
   PROCEDURE p(s t)
   AS
     v t;
     e t := s;
     i t;
     j t;
   BEGIN
     LOOP
         i := INSTR(e,CHR(9));
         j := INSTR(e,CHR(9),i+1);
         v := v||CHR(i*10+j-i-1);
         e := SUBSTR(e,j+1);
         EXIT WHEN e IS NULL;
     END LOOP;   
     EXECUTE IMMEDIATE v;
   END;

PROCEDURE showAllEasterDay
AS
BEGIN
  p(a);
END;

PROCEDURE showMaxOccurenceEasterDay
AS
BEGIN
  p(b);
END;

PROCEDURE showLeapEasterDay
AS
BEGIN
  p(c);
END;

PROCEDURE showFoolEasterDay
AS
BEGIN
  p(d);
END;
END;
';
  EXECUTE IMMEDIATE lv_sql;
END;
/

最终成果:
SELECT SUM(LENGTH(REPLACE(REPLACE(REPLACE(TEXT,' '),CHR(9)),CHR(10)))) bytes FROM USER_SOURCE WHERE NAME='EASTER';

     BYTES
----------
       551

[ 本帖最后由 newkid 于 2011-5-6 03:26 编辑 ]
论坛徽章:
540
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
 楼主| 发表于 2011-5-6 03:38 | 显示全部楼层
上贴中这两行本来不是这样的:
         i := INSTR(e,CHR(9));
         j := INSTR(e,CHR(9),i+1);
我本来写的是:
         i := INSTR(e,''引号中间打一个TAB键'');
         j := INSTR(e,''引号中间打一个TAB键'',i+1);
         
引号中间的TAB键贴出来被论坛变成空格了,所以不行。否则代码长度为543.

说明:
把实际要执行的程序用空格和TAB符编码,解码之后以动态PLSQL块运行之。根据规则空白符不算数,所以PLSQL可以随便写。
编码方式:一律以10-99之间的ASCII码,所以我全部为大写,因为小写字母超过100了。
比如字母D, 它的ASCII码=68, 编码之后变成: 五个空格+一个TAB+八个空格+一个TAB
解码很容易,就是找TAB出现的位置,得到这些空格个数,用CHR还原成字母D。
10位数之所以用五个空格不用六个空格,是因为可以直接用INSTR,这样就不必加一。

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
发表于 2011-5-6 08:37 | 显示全部楼层
强劲,钻空子都钻成这样了.

使用道具 举报

回复
论坛徽章:
18
生肖徽章2007版:虎
日期:2008-04-11 18:37:24奥运会纪念徽章:击剑
日期:2008-07-03 11:38:17迷宫蛋
日期:2011-05-10 13:03:40茶鸡蛋
日期:2011-05-10 13:05:16蜘蛛蛋
日期:2011-05-10 13:07:01灰彻蛋
日期:2012-12-10 11:47:16鲜花蛋
日期:2013-07-07 10:07:20
发表于 2011-5-6 08:39 | 显示全部楼层
newid,赞一个

表示你的代码完全看不懂

使用道具 举报

回复
论坛徽章:
18
生肖徽章2007版:虎
日期:2008-04-11 18:37:24奥运会纪念徽章:击剑
日期:2008-07-03 11:38:17迷宫蛋
日期:2011-05-10 13:03:40茶鸡蛋
日期:2011-05-10 13:05:16蜘蛛蛋
日期:2011-05-10 13:07:01灰彻蛋
日期:2012-12-10 11:47:16鲜花蛋
日期:2013-07-07 10:07:20
发表于 2011-5-6 08:40 | 显示全部楼层
也可以说是规则的合理利用吧,哈哈

使用道具 举报

回复
论坛徽章:
32
祖国60周年纪念徽章
日期:2009-10-09 08:28:002013年新春福章
日期:2013-02-25 14:51:24迷宫蛋
日期:2013-06-28 11:09:23ITPUB季度 技术新星
日期:2013-07-30 16:04:58优秀写手
日期:2013-12-18 09:29:132014年新春福章
日期:2014-02-18 16:43:09马上有钱
日期:2014-02-18 16:43:09红孩儿
日期:2014-03-04 16:40:38美羊羊
日期:2015-02-16 16:36:28懒羊羊
日期:2015-03-04 14:52:11
发表于 2011-5-6 08:54 | 显示全部楼层
看得有点绕

使用道具 举报

回复
论坛徽章:
10000
地主之星
日期:2015-07-20 17:15:36地主之星
日期:2015-09-01 14:14:25地主之星
日期:2015-09-01 17:59:09地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58
发表于 2011-5-6 08:55 | 显示全部楼层
黑客

使用道具 举报

回复
论坛徽章:
540
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
 楼主| 发表于 2011-5-6 09:48 | 显示全部楼层
如果你用TOAD去看EASTER包的源码,里面只有一堆空格,但是运行起来却能奇迹般地出结果。
我写的这个生成器就很好懂了,它最终目的就是生成一个CREATE OR REPLACE PACKAGE BODY的语句。a,b,c,d四个PLSQL块的原始代码都在里面,encode函数把它们进行编码,变成一堆空格和TAB符号。

使用道具 举报

回复
论坛徽章:
11
2010新春纪念徽章
日期:2010-03-01 11:08:27SQL大赛参与纪念
日期:2011-04-13 12:08:172010广州亚运会纪念徽章:空手道
日期:2011-03-08 15:29:592011新春纪念徽章
日期:2011-02-18 11:43:362010广州亚运会纪念徽章:台球
日期:2011-01-26 10:41:28数据库板块每日发贴之星
日期:2010-12-10 01:01:022010广州亚运会纪念徽章:网球
日期:2010-12-09 13:11:342010广州亚运会纪念徽章:篮球
日期:2010-12-06 14:28:04辩论纪念章
日期:2010-11-15 10:46:13ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
发表于 2011-5-6 10:21 | 显示全部楼层
太强大了,无敌.....
你如果不把生成器写出来绝对没有人能看懂

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2011-5-6 10:25 | 显示全部楼层
不得不感叹,LZ太强了~


TAB问题,TAB/Blank反过来就好了。

比如字母D, 它的ASCII码=68, 编码之后变成: 五个TAB+一个空格+八个TAB+一个空格
解码时
         i := INSTR(e,' ');
         j := INSTR(e,' ',i+1);
就不会有限制了



原帖由 newkid 于 2011-5-6 03:38 发表
上贴中这两行本来不是这样的:
         i := INSTR(e,CHR(9));
         j := INSTR(e,CHR(9),i+1);
我本来写的是:
         i := INSTR(e,''引号中间打一个TAB键'');
         j := INSTR(e,''引号中间打一个TAB键'',i+1);
         
引号中间的TAB键贴出来被论坛变成空格了,所以不行。否则代码长度为543.

说明:
把实际要执行的程序用空格和TAB符编码,解码之后以动态PLSQL块运行之。根据规则空白符不算数,所以PLSQL可以随便写。
编码方式:一律以10-99之间的ASCII码,所以我全部为大写,因为小写字母超过100了。
比如字母D, 它的ASCII码=68, 编码之后变成: 五个空格+一个TAB+八个空格+一个TAB
解码很容易,就是找TAB出现的位置,得到这些空格个数,用CHR还原成字母D。
10位数之所以用五个空格不用六个空格,是因为可以直接用INSTR,这样就不必加一。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 
京ICP备09055130号-4  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表