楼主: newkid

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

[复制链接]
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
11#
 楼主| 发表于 2011-5-6 22:25 | 只看该作者
感谢猪猪提醒,把空格和TAB对调之后发贴就没问题了。
此外去掉了abcd四个辅值改为用字符串常量传参,学习nyfor的e=e方法代替NOT NULL判断,增加了2011,2099作为动态PLSQL绑定变量,现在是525 bytes了。

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(CHR(9),TRUNC(lv_asc/10)-1,CHR(9))||' '||LPAD(CHR(9),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 Y1-1901+LEVEL N FROM (SELECT :Y1 Y1,:Y2 Y2 FROM DUAL) CONNECT BY LEVEL<Y2-Y1+2)
           )
    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 Y1-1901+LEVEL N FROM (SELECT :Y1 Y1,:Y2 Y2 FROM DUAL) CONNECT BY LEVEL<Y2-Y1+2)
                                      )
                              )
                      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 Y1-1901+LEVEL N FROM (SELECT :Y1 Y1,:Y2 Y2 FROM DUAL) CONNECT BY LEVEL<Y2-Y1+2)
                  )
           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 Y1-1901+LEVEL N FROM (SELECT :Y1 Y1,:Y2 Y2 FROM DUAL) CONNECT BY LEVEL<Y2-Y1+2)
                       )
              )
         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);
  
   PROCEDURE p(s t)
   AS
     v t;
     e t := s;
     i t;
     j t;
   BEGIN
     WHILE e=e LOOP
         i := INSTR(e,'' '');
         j := INSTR(e,'' '',i+1);
         v := v||CHR(i*10+j-i-1);
         e := SUBSTR(e,j+1);
     END LOOP;   
     EXECUTE IMMEDIATE v USING 2011,2099;
   END;

PROCEDURE showAllEasterDay
AS
BEGIN
  p('''||encode(a)||''');
END;

PROCEDURE showMaxOccurenceEasterDay
AS
BEGIN
  p('''||encode(b)||''');
END;

PROCEDURE showLeapEasterDay
AS
BEGIN
  p('''||encode(c)||''');
END;

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

测试:
EXEC easter.showAllEasterDay;            
EXEC easter.showMaxOccurenceEasterDay;   
EXEC easter.showLeapEasterDay;
EXEC easter.showFoolEasterDay;

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

     BYTES
----------
       525

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
12#
发表于 2011-5-7 13:33 | 只看该作者
果然有人利用不计算空格的不合理规则钻了如此大的一个空子,震惊啊!
下计算次数时,先将tab换成空格,行首连续空格替换为空字符串,然后再计数,这样的规则就更公平合理了

使用道具 举报

回复
论坛徽章:
226
BLOG每日发帖之星
日期:2010-02-11 01:01:06紫蛋头
日期:2013-01-12 23:45:222013年新春福章
日期:2013-02-25 14:51:24问答徽章
日期:2013-10-17 18:06:40优秀写手
日期:2013-12-18 09:29:10马上有车
日期: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:14
13#
发表于 2011-5-7 18:28 | 只看该作者
其实我的代码中也用空格在动态SQL中替换了比较长关键字
当时也想过可以利用空格和回车的配合来将经常出现的关键字都替换掉,不过时间所限没有实现。

没想到newkid和00整得如此彻底,将所有的字符都替换了

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
14#
发表于 2011-5-7 21:41 | 只看该作者
原帖由 lastwinner 于 2011-5-7 13:33 发表
果然有人利用不计算空格的不合理规则钻了如此大的一个空子,震惊啊!
下计算次数时,先将tab换成空格,行首连续空格替换为空字符串,然后再计数,这样的规则就更公平合理了

章还没有发?

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
15#
 楼主| 发表于 2011-5-7 22:58 | 只看该作者
原帖由 lastwinner 于 2011-5-7 13:33 发表
果然有人利用不计算空格的不合理规则钻了如此大的一个空子,震惊啊!
下计算次数时,先将tab换成空格,行首连续空格替换为空字符串,然后再计数,这样的规则就更公平合理了

没用的,我照样钻空子,只要另起一行你就以为是行首空格了
除非把TAB计入字符数。这样只有换行和空格不算数,但是换行无法作分隔符,因为PLSQL在编译的时候会自作聪明地去掉行尾空格。

使用道具 举报

回复
论坛徽章:
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
16#
发表于 2011-5-8 09:40 | 只看该作者
关于空格的计算问题,写个小PLSQL代码段来解析是否为字串中的空格就行,而且也不难.

使用道具 举报

回复
论坛徽章:
69
奥运会纪念徽章:射击
日期:2016-09-06 23:08:25马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:112013年新春福章
日期:2013-02-25 14:51:24复活蛋
日期:2013-02-18 11:25:01迷宫蛋
日期:2012-12-25 17:17:41复活蛋
日期:2012-12-21 17:41:38奥运会纪念徽章:沙滩排球
日期:2012-10-27 14:59:31ITPUB 11周年纪念徽章
日期:2012-10-09 18:03:32
17#
发表于 2011-5-8 09:41 | 只看该作者
强啊

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
18#
发表于 2011-5-8 15:22 | 只看该作者
原帖由 nyfor 于 11-5-8 09:40 发表
关于空格的计算问题,写个小PLSQL代码段来解析是否为字串中的空格就行,而且也不难.


正则表达式就更简单一些,可以一行显示,下次要堵住这样的问题

[ 本帖最后由 lastwinner 于 2011-5-8 20:35 编辑 ]

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
19#
 楼主| 发表于 2011-5-9 02:42 | 只看该作者
原帖由 nyfor 于 2011-5-8 09:40 发表
关于空格的计算问题,写个小PLSQL代码段来解析是否为字串中的空格就行,而且也不难.

确实如此,不过解析时得考虑连续的单引号、Q-QUOTE等东西,还是挺罗嗦的。

使用道具 举报

回复
论坛徽章:
7
数据库板块每日发贴之星
日期:2009-07-24 01:01:02数据库板块每日发贴之星
日期:2010-09-29 01:01:01ITPUB9周年纪念徽章
日期:2010-10-08 09:31:212011新春纪念徽章
日期:2011-02-18 11:43:362012新春纪念徽章
日期:2012-01-04 11:50:44ITPUB 11周年纪念徽章
日期:2012-10-09 18:05:372013年新春福章
日期:2013-02-25 14:51:24
20#
发表于 2011-5-21 10:02 | 只看该作者
以后要每天都跟着学习了,不然太落后了

使用道具 举报

回复

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

本版积分规则 发表回复

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