Javascript 中几种数组赋值的区别及=号的作用

Javascript中,目前要把一个数组的内容等于另一个数组,我会的手段大致有三种:

  1. a = b;

  2. a = b.slice(0);

  3. b.forEach(function(element){ a.push(element);});

这三种有什么不同呢?

 

这三种写法的不同究其原因都出在=号的作用上。数组间的等号可以认为是一个别名。也就是 a = b 的效果等同于 b.alias => a, 给 b 取了个叫a的别名。数组还是同一个数组,多了个名字而已。于是不论用名字 a 操作还是用名字 b 操作,改变的都是同一个数组,换个名字都能看到效果。比如:

var b = [1];
var a = b;
a.push(2);
b.push(3);
console.log(a);  //[1,2,3]
console.log(b);  //[1,2,3]

而 b.slice(0) != b 本身, 只是等于 b 的内容。 a = b.slice(0); 相当于先 new 了一个新的匿名 array,内容为 b 的内容,然后取了个名字叫 a。因为是new出来的,所以用 a = b.slice(0) 后,操作 a  和操作 b 是操作两个不同的数组。

 

那么,什么时候用第三种呢?要用第三种,很明显,首先 a 必须是一个已经存在的数组,不然会报 undefined。第三种的使用场景有比如这样的:

var a = [];
var b = [1];
var c;
afunction(a){ c = a;};  //一个函数,使用a作为传入参数,只调用一次

//此时想把 b 的值赋给c。

因为 c 只在函数体内才能被赋值,而这个值只能通过a来进行。 如果用 a = b, 那么效果等同于 (Original Array a) . removeName(a), 然后 b.alias(a);  而 c 依然是那个 Original Array a,只是丢失了原本a这个名字,只剩下c这个名字了。类似的,如果用 a = b.slice(0), 也无法改变c,只是让c这个数组丢失了另一个叫a的名字而已。这时候,用第三种,把 b 的内容逐个加到已有的 a 里面,才能同时操作到 c。

 

装了个Octave

装了个Octave,用来做些题目。但是遇到了一些问题,结果不是很理想。

先是在Linux下装的。用的Gentoo,有些USE是去掉的。于是乎,最后装好的样子就是不能生成图形,也不能看help。不能生成图形是有心理准备的,因为我的Gentoo连X都没装,gtk 和 qt 也都是去掉的。不能生成help则是因为doc这个USE Flag被去掉了。如果加回去,则需要装很大一堆包,包括几个X的和几个Tex的,感觉太小题大做了。

于是,加上看着这个软件的计算功能还不错,本着用来代替Windows自带计算器的想法,准备装到Windows上去。我用的Windows8,使用了那个for VS2010的setup.exe来安装。装好后不能用…… 一查,发现这个在Windows8下还需要做点fix,需要在启动的时候加一个 -i --line-editing。 于是乎,加了,然后再打开。这下基本可以正常用了。可惜,想用于代替calc还是不太靠谱。原因无它,速度太慢了。打开慢,生成图像也慢。几十秒才能出结果,这简直无法接受。

但是我看别人好像并没有遇到“慢”的问题。不知道原因何在。是因为Windows8?还是因为我的jre不太对?我的jre装完后,只能执行java,一旦输入java -v 会直接告诉你不能生成VM,让人很囧。

我还有一台Windows8.1的机器,一会去试试看能否有改观。

Total War: Rome II Pack file Specification

From 00h

Header:

4 bytes  String  "PFH4"     -----PFH0 in ETW, NTW and S2TW, sometimes PFH1,  but now it is PFH4.

4 bytes  Int32   PackType  ------ In R2TW, all the types so far have appeared are 40, 01, 02, 11, 12

4 bytes  Int32   IsPatch?   ----- 1  means it is a patch or something of this kind, following another pack.

4 bytes  Int32   Length Of the Name of the Pack it following 

4 bytes  Int32   Amount of File ---- Indicating how many files exist in this pack.

4 bytes  Int32  Length of IndexTable  -------IndexTable is the next section, contains all of the filenames and the length of every file.

4 bytes  xx       Unknown. ---- Maybe it means the 4 of  "PFH4"

-----------------------------------------------------------------------------------

Optional:  The Name of the Pack it following,  exists only when the "IsPatch" is 1

n bytes  String  Name of the Pack it following.   n = "Length Of the Name of the Pack it following "

-----------------------------------------------------------------------------------

IndexTable:

4 bytes Int32  Length of the File  --------"the File" means the file associated with the filename directly followed.

n bytes Null-terminated ASCII String   Filename  ----------ended with a 0x00

.......... a "Length of the File" and a "Filename" is a group, presents the infomation of a file............

........... and this kind of group continues, until it meets the length that has been determined by "Length of IndexTable" in the Header section.............................

----------------------------------------------------------------------------------

Body:

n bytes binary  Continuous File Data without alignment. ------------- n is determined by the "Length of the File" in IndexTable section, and so is one file.

............. Continue, till the end of pack.

 

近期的语音练习

最近,其实说近也不近,大致估算也有一年多了,对语音的兴趣十分浓厚,并勤于练习。大多数时间是在练习颤音,主要是拉丁语的颤音r。这个音在西班牙语和意大利语里面也有,西班牙语是rr,意大利语是r,以意大利的更标准一些。这个音练习到现在也没怎么练好。不断地练习、反馈、学习、琢磨之中,经常有新的发现。目前已经失去对“正音”的判断能力。我能发出跟各种视频,音频很相似的声音,但是各种视频、音频里面展示的发音各不相同,这让我很是困惑。有种说法是,Classic Latin 的读法中,但凡有r的地方,都是需要发颤音的。我听的Wheelock的前两课的词汇里面,确实也是这么做的。然而这样会让很多词变得非常难念。比如各种 -re结尾的就会很难听,而以 -r 结尾的更让人别扭。两者结合的诸如 conservare 这样的,单个词念一下也就罢了,放在句子里面经常让人卡住。LLPSI的音频里面,则是很多r 都念得跟英语的r 差不多,听不到明显的颤音。各种歌曲资料也难以参照。 Libera 之类的合唱团,完全是英语念法,倒是可以直接排除;帕瓦罗蒂那种就纠结了,他有些地方发得颤音很明显,有的地方又听不出来;美国的神童女 Jackie Evancho的颤音很到位,我感觉她的拉丁语发声都比她的英语要好了;意大利人的组合 Rhapsody,估计是意大利语的关系,颤音也很销魂,听起来感觉就是在舌头尖上打转的那种,而我则办不到这一点,造型部位要更接近上颚,弄得跟翘舌似的。

由颤音r引入的,我学习了很多关于语音的知识。比如英语的r跟汉语的r是不同的,西班牙语也有自己的一个r的念法。西班牙语不少发音都有自己的特点,d 就不能按照英语的 d 来念,粗听类似,但发声要领有区别。粗听都不同的也有,比如 j,发跟 英语 h 类似的音,不过又不是完全等于 h,跟英语的j则是完全不搭边。欧洲国家虽然大多都用拉丁字母,但各种字母的表音却各有一套,望文辩声完全不靠谱,由此我又进一步学习了IPA,企图能得到一个统一的表音符号体系。起初一切都良好,除了我不会在电脑上打出IPA符号,除了不少IPA符号表示的音我发声有困难辨析有困难之外都好。可是,再进一步了解之后,我发现这也是一个坑。不同年代不同版本的IPA符号经常互相混淆。傻傻分不清的音从r等少数几个开始有扩散的趋势。比如元音的i,比如元音的o。一个地方有一个地方的记法。就是那个 r ,在英语中的 r,不考虑各地口音,单单 英国RP口音的 r,都有好几种表示。有的写成 r,有的写成 ɹ,但是跟 ɹ 在一张表里也有一个 r ,两者不是同一个音啊。

在迈入了语音学的大门之后,其实我也不知道算不算入了门,姑且就算吧,之后,了解的概念越来越多了。什么尖团音啊,擦音啊塞音啊,清浊对立啊之类的。有些很容易学习很容易辨别,有些则困难些。比如清浊声,也就是voiceless 和 voice 的,汉语普通话没有清浊对立,只有送气和不送气的对立;英语则清音大多都送气,浊音都不送气。这样就很容易把汉语的送气不送气对立直接套用到英语清浊音里面,用送气与否来代替 voiceless 与否。实际上,汉语拼音里面的b跟英语里面的b是不同的,d跟d也不同,g和g也不同。了解到这个事实后,我经常在反省,到底我自己用的是正确的发音吗?我母语是吴语,对于清浊对立倒并没有障碍,吴语的 '把' 是清音b,'白' 是浊音 b,'搭'是清音d,'夺' 是浊音d。这个我在说吴语的时候可以发得自然和谐毫无压力,然而,沿用到汉语普通话的时候,我对于拼音b开头的,用的是清音吗?在说英语的时候,对于字母b开头的,我念的是浊音吗?我发现我两者都不能肯定…… 我逐渐发现,至少在讲英语的时候,我对于b开头的,有些时候用的是清音,多数时候用的是浊音,g开头的,清音更多些,d则比较混乱。我于是开始逐词逐词地训练,然而在念每个词的时候,心里都惦记着那一堆堆的发音规则,真心是件很累人的事情啊,连话都不会说了。所幸,目前貌似已经拥有了辨析出别人的发声是清还是浊的能力。比如这首姚斯婷的《走进莎莉花园》,她用的就是清音,让我听了巨别扭,有种心里发痒没得挠的感觉。不过这个未经严格检验,改天应当弄一些不送气清音和送气浊音来辨析。据说原始印欧语有不少音是送气浊音,比如bhrater,这种费劲的音我都不明白怎么发出来,估计当年的人说得也费劲,于是后来这bh就音变成了b,最后转化到了英语的brother。

写了这么多,其实今天原本就想记录一个新找到的网站来着…… http://www.uiowa.edu/~acadtech/phonetics/english/frameset.html  美国英语发音的详细图解+音频。图很不错,动态的,各种细节都涉及到了。

PLS-00801: Type xxxxxx has no MAP method 这到底是啥啊……

前段时间把一个查询效率很低的视图给改成了 带一个日期参数的函数,输入一个日期,返回相应的结果集。但是这样没能完整地复制视图原有的功能,比如给定一个日期区间的查询就做不到了。于是今天给扩充了一下,然后就遇到了这个该死的莫名其妙的PLS-00801.

代码呢是这样的:

create table stockstructure (
     oc_date         NUMBER(10) ,
     exchange_type   CHAR(4) ,
     stock_code      CHAR(12) ,
     total_amount    NUMBER(20,3),
     turnover_amount NUMBER(20,3) ,
     remark          VARCHAR2(2000 )
  );

create or replace type rec_stockstructure is OBJECT(
     oc_date         NUMBER(10 ) ,
     exchange_type   CHAR(4 ) ,
     stock_code      CHAR(12 ) ,
     total_amount    NUMBER(20 ,3),
     turnover_amount NUMBER(20 ,3) ,
     remark          VARCHAR2(2000 )
  );

create or replace type ty_stockstructure is table of rec_stockstructure;

create or replace function fn_get_stockstructure(
     p_oc_date hstype.HsDate,
     p_end_date hstype.hsdate default 0
  )
return ty_stockstructure
is
    tmp_stockstructure ty_stockstructure := ty_stockstructure();
    rs_stockstructure ty_stockstructure := ty_stockstructure();
begin
    if p_end_date = 0 then
       select rec_stockstructure(p_oc_date,a.exchange_type,a.stock_code,a.total_amount,a.turnover_amount,a.remark)
          bulk collect into rs_stockstructure
         from stockstructure a
       where (a.oc_date,a.exchange_type,a.stock_code) in
                   ( select max (t.oc_date),t.exchange_type,t.stock_code from stockstructure t
                    where oc_date<=p_oc_date
                      group by t.exchange_type,t.stock_code
                   )
              ;
    else
         for xdate in 0..(to_date(p_end_date,'yyyymmdd' )-to_date(p_oc_date,'yyyymmdd')) loop
                select rec_stockstructure(to_char(to_date(p_oc_date,'yyyymmdd' )+xdate,'yyyymmdd'),a.exchange_type,a.stock_code,a.total_amount,a.turnover_amount,a.remark)
                  bulk collect into tmp_stockstructure
                 from stockstructure a
               where (a.oc_date,a.exchange_type,a.stock_code) in
                           ( select max (t.oc_date),t.exchange_type,t.stock_code from stockstructure t
                             where oc_date<=to_char(to_date(p_oc_date,'yyyymmdd' )+xdate,'yyyymmdd')
                            group by t.exchange_type,t.stock_code
                           )
                ;
               rs_stockstructure := rs_stockstructure multiset union tmp_stockstructure;    --------------------- 报错位置
          end loop ;     
    end if;        
   return rs_stockstructure;
end;

然后就在我标着的位置给抛出了一个错误。错误原文如此:

Error: PLS-00801: internal error [*** ASSERT at file pdw4.c, line 2079; Type 0x0x2b89f96a66e0 has no MAP method.; 

于是我就纠结了,这到底说的是啥呢?这几个关键字我连搜索都没法搜。而且更纠结的是,在Oracle 11g 上不报错,在 Oracle 10g 上报错。那么是版本问题嘛?我查了下,10g multiset 的支持完全没问题啊。我又在报错的这个数据库上做了个这样的测试:

select * from table( 
   ty_stockstructure(rec_stockstructure(1234,'1','1234',1,1,'1')) 
  multiset union 
   ty_stockstructure(rec_stockstructure(2234,'2','2234',2,2,'2')) 
)

结果也是好好的,完全符合预期。真是无厘头啊,这都什么情况啊……

跪求一个证明我错了的用例……

这两天无聊刷HDOJ,各种不爽啊。C语言果然是忘记光了。

今天遭遇1003题。这题网上一搜倒是一堆讨论的,全是不知道自己死在哪的。而回复则大多是“这是一道典型/经典/简单的动态规划题”,然后给个AC的代码。我不知道动态规划是什么,当年学的时候没注意听就算听了现在也早忘记掉了,但是你给个正确的代码并不能表示我的就是错的啊…… 如果说错了,那么到底错哪里呢…… 跪求一个能证明我错了的测试用例……

HDOJ 1003 题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1003

我的代码:

 

#include <stdio.h>

int main(){
    int times, numbers;
    long a, result, pretend;
    int i,j,s,e;

    scanf("%d",&times);
    for(i=1;i<=times;i++){
        scanf("%d",&numbers);
        scanf("%ld",&a);
        result = a; 
        pretend = a; 
        s = 1; 
        e = 1; 
        for(j=2;j<=numbers;j++){
            scanf("%ld",&a);
            pretend += a; 
            if(pretend>result){
                result = pretend;
                e = j; 
            }  
            if(a>result){
                result = a; 
                s = j; 
                e = j; 
            }  
        }  
        printf("Case %d:\n%ld %d %d\n",i,result,s,e);
        if(i!=times){
            printf("\n");
        }  
    }  
    return 0; 
}

 

----- 2013.02.01 P.S.-------------------

因为不知道DP具体是个啥,今天抽空查了些资料,草草研究了下DP究竟是怎么回事,并参考了别人的一些代码,虽然错误用例还是没能找到。 我的代码的算法大致可以这样描述吧:

          MaxSum[1] = ValueN[1];

          MaxSum[n] = (MaxSum[n-1]+ValueN[n]>MaxSum[n-1]? MaxSum[n-1]+ValueN[n]: MaxSum[n-1]) > ValueN[n] ? $1: ValueN[n]

$1 表示 前一个判断得到的结果。

第一个判断 MaxSum[n-1] + ValueN[n] > MaxSum[n-1] ?  只要 ValueN[n] >0就能成立

第二个判断 MaxSum[n-1] + ValueN[n] > ValueN[n],成立条件是 MaxSum[n-1] > 0,第二个判断的另一个分支 MaxSum[n-1] > ValueN[n] 则不能直接看出正负关系,但是因为要走到这个分支,必然要求ValueN[n]为负,要小于一个负数的话,MaxSum[n-1] 必然也得是负数,这样才能让条件不成立从而得到ValueN[n]。换句话说,只要 MaxSum[n-1] >0, 第二个判断得到的结果都是 MaxSum[n-1] + ValueN[n] 或者 MaxSum[n-1]。

写成这样了之后,看上去好像也是个DP吧…… 不知道有没有高人能给分析分析。

   

要注意Perl系统变量值的变化

忘了专业点的说法怎么叫了,这里说的系统变量就是指那些 $_, $1, $# 之类的默认设置了的变量。一直以来被告诫要注意的是$_这个变量,一个while循环一个if判断什么的,有可能改变它的值。因为一直注意,倒也没遇到太大障碍。

今天栽在另一个变量上了,$1。语句是这样的:

s/$1/$hash{$1}/gi if /(\w+)/;

执行后发现总是被替换为空字符串。难道是 hash里面没值?我于是改成了:

 s/$1/$hash{$1}/gi if (/(\w+)/ && defined $hash{$1} );

结果还是一样。

进行调试,把相关的值都打出来,发现各个值都取得完全没问题,唯独在 s/xxx/yyyy/gi 这步上出错了。

仔细观察了下substitution的形式特征,我想起来xxx这部分可以是regex的,比如我常用来交换位置的那种做法:

  s/(xxx)(yyyy)/$2$1/g

在这样一句中,很明显 $1,$2的值由前面所决定。回到我出错的这句,估计也是这个原因了。第一个 $1,它取的if中的regex捕捉到的内容,第二个 作为hash的key的$1,它取的是xxx这个位置捕捉的内容。(话说xxx这个位置专业点的叫法是啥来着……)。做个实验验证下:

if (/(\w+)/ && defined $hash{$1} ){

  $replacement = $hash{$1};

  s/$1/$replacement/gi;

}

实验通过,这样果然管用。

 

 

个税的Oracle一句SQL算法

没啥技术含量,其实就是一个对 model 用法的练习……

WITH AAA AS (
  select 0 AS start_value, 3500 AS end_value, 0.0 ratio from dual
  union select   3500 , 5000, 0.03 from dual
  union select   5000 , 8000, 0.1 from dual
  union select   8000 , 12500, 0.2 from dual
  union select   12500 , 38500, 0.25 from dual
  union select   38500 , 58500, 0.3 from dual
  union select 58500 , 83500, 0.35 from dual
  union select 83500 , NULL, 0.45 from dual
)
SELECT (XX -start_value)*ratio + quick_num FROM (
   SELECT start_value,decode(end_value, 0 , NULL ,end_value) AS end_value,ratio, quick_num FROM (
      select row_number()over(order by start_value) rn,
              nvl(lag(end_value-start_value)over( order by start_value),0)*nvl(lag(ratio)over(order by start_value),0) quick_num,
              start_value, end_value,ratio
        from AAA
) a
  model
   dimension by (rn)
    measures (quick_num,start_value,end_value,ratio) IGNORE NAV
   RULES
     (quick_num[ ANY ] ORDER BY rn = quick_num[cv(rn)- 1] + quick_num[cv(rn)],
      start_value[ ANY ] = start_value[cv(rn)],
      end_value[ ANY ] = end_value[cv(rn)],
      ratio[ ANY ] = ratio[cv(rn)])
)
WHERE XX >= start_value AND ( XX < end_value OR end_value IS NULL )

XX为工资收入扣除各种保险和住房公积金后的数目。总共出现了三个XX,都需要替换。其实做个函数比较好,不过那就不是一句了。

mplayer在Gentoo下的默认显示语言

在Gentoo中使用mplayer遇到一个莫名其妙的问题,我的locale一律全是en_US.UTF-8, 输入 "mplayer" ,它给出的回显文字却全是中文的。查看了一下 mplayer 的USE标记,里面也没有任何跟 语言 有关的,安装时也没说要 LINGUAS 的。

我的LINGUAS设置的是“zh_CN zh_TW jp en”,看来看去就这里可能是原因所在,不然的话难道会是 时区? 于是实验了一下,把 LINGUAS 改成了 “en zh_CN zh_TW jp”,然后重新emerge 了一次,再输入mplayer,这次它给的回显就正常了,全是英文了。

这个特性很坑爹,记录一下。

改了个WOW插件-法师自动补全施法材料

开始重操旧业玩起了WOW,只不过这次玩的是法师。法师有三种施法材料:魔粉,传送符文,传送门符文。用光了会被人质疑为不够专业。材料在包裹里20个一组占一个格子,所以一次买的时候最好买齐20个,省的老是回来补。手动买其实也没啥不方便的,不过能自动还是自动吧,懒人自然有懒想法。

这个功能倒是很常见的功能了,从古到今,带这功能的各种插件和宏都流传了不少。不过我这不是没装嘛。特地去为了这点事情而找个东西,实在太费劲了,不如自己直接添上。我在已经装了的一个叫AutoRepair的插件上开始修改。AutoRepair,顾名思义就是自动修理装备用的,修理装备会需要打开商店界面,用到MERCHANT_SHOW这个事件,这样就省得我自己去注册了。

Read more

遇到一段跑起来费解的代码

今天校准数据库的时候,发现了一个执行结果不同的现象。经过定位,发现问题出在下面这段代码上。这段代码的执行结果被一个v_request_num的变量所左右。 v_request_num 越小,最后的结果就越少, v_request_num 越大,最后的结果就越多。如果说单次执行的话,这个是废话。但多次执行,直到将表中数据计算完毕后的结果也是这样,着实费解。

 

Read more

Fundjour的数据结构

先设计好数据结构,然后在数据库里把表建立起来。这样即使前端部分还在写,我一样可以通过直接操作SQL来记录需要记录的东西,可以给前端部分的开发更多的时间。

一条记录的字段应当大致有这样几个:

ID     作为每笔收支的真正的标识符

DATE  日期

TIME   时间

BALANCE  数额

TYPE  币种

IO   收或支,标记一个方向

FT   From/To,记录从哪里来或者到哪里去

USAGE  用途,缘由

日期和时间那里是分开还是合并呢?各有优劣。暂时先决定分开吧,以后看情况。

以上是一条记录应当有的结构。如果建表的话,还需要加入两个字段,一个是表主键,一个是记录的时间。加入表主键而不使用记录的那个ID是因为我想让记录的ID保持紧凑中间不要跳号。表主键就无所谓了。不过这点也许还需要再考虑。 加入记录时间则是因为发生时间和记录时间肯定会不一致的。都在当天也就罢了,要是隔天记录的话,只有一个时间会让统计失去意义的。

最后应当大致如此:

CREATE TABLE fundjour (

  ID  int ,  --- primary Key

  RID int,   -- record id

  DATE  date ,

  TIME  date,

  BALANCE number,

  TYPE varchar,

  IO  int,

 FT  varchar,

 USAGE varchar,

RECORD_TIME date default sysdate  -- 记录时间

)

 

 

准备写个记账用的东西

准备写个记账用的东西,不然不利于培养理财意识。已经半只脚在金融界的了,总得专业点吧。

带图形界面的编程是我的弱项,短时间内根本没法解决,索性回避吧。直接写个命令行操作的,用起来也能更省事更随心所欲一些。

这个东西的要求首先得要足够简洁和方便。每次打字一定要足够少。不然我直接往数据库里写SQL,功能还能更强大更灵活一些。然后得足够地灵活,不要太死板地限制我的输入。虽然多数时候我要求打字少,但也应当支持我话痨的时候。这个东西的功能暂时不需要太多,太多我也想不出来,只要基本的吧。大致应该有以下几个:

1. 资金来往记录的增删查改。

2. 各种分类统计功能。

技术选型还没想好。是把账目都写在文本里面还是弄到数据库里面去也没想好。这个一边做一边考虑吧。先描绘下想要的效果:

1.名字初定为fundjour,命令行输入fdj可调出。

2.调出来的当以 fdj > 打头,其后可输入具体指令操作。

2.1. 操作的指令不要写死,应当有一张列表,可随时修改。

2.2. "fdj > got 3000RMB: expense of Sep."  类似这样的一条表示入账了3000块。冒号后面为原因。这个冒号后面为因由就定死吧,太灵活的话写起来会比较困难。

2.3. 因为操作指令不写死,那么自然应当支持多种同义词。比如说 "fdj > add 3000RMB" 

2.4. 应当支持多点废话,比如说"fdj > I got 3000RMB from company for expense of Septempber"。 这里应当能够正确识别出关键字"got","from","for"。 当然这个要先写到操作指令列表里面去。最前面那个纯废话的"I",应当能被无视。

2.5. 是否应当支持颠倒的顺序呢?还在犹豫…… 比如说 "From company I got 3000RMB as expense of September", 这样的应当可以支持吧,但是那个"I" 在这里会比较碍事。 而另一种比如说"Company paid me 3000RMB as expense of September" 这样的,我暂时没办法解析了。算了,颠倒顺序这点就先砍掉吧,等我在自然语言处理上有所成了再回炉。

3. 应当支持直接以命令方式使用,不需要先行进入fdj > 的shell。 命令方式的格式如下:fdj [detail]。比如说" fdj got 3000RMB "。 如果 [detail]为空白,那么默认显示当前月份的账目。

4. 上面写的时候设想的场景都是增加一条记录的,但这个是最简单的。其他的查删改都要难一些。查的话,关键操作符还是一样,由列表指定,具体查询条件应当支持 (1)时间和时间段,(2)缘由的模糊匹配,(3)大致的类别,(4)金额区间,(5)入账出账,(6)分类统计的输出。 具体怎么实现是个问题,就连怎么区分这6类也是个需要考虑的问题。给六类分别指定个不同的指令么?还是带参数?还是统统写在一起让它自己解析?

5.删除功能不需要太灵活。删除的作用本质上是删掉误输入的记录。就给两种格式吧:(1)删除上N条。或者删除上N至M条,或者删除上N,M,X,Y,Z条,或者多个区间。(2)删除记录的某个ID号,某个ID区间,某几个ID号,某几个ID区间。

6.修改功能还没想好。感觉这东西要按命令行的方式来操作的话有点类似在ed中编辑一样,会很憋屈。要不要考虑把那要改的记录搞进vim里,然后改完保存了再提交回去呢?

7. 各种查询统计,也放到指令列表里,对应到具体的统计方式。这货应当是个不断扩展的,光凭现在想必然没法想全了。到时候想到一个加一个进去吧,方便扩展。

 

从上面看,似乎不用数据库不太现实了。那就弄个数据库吧。前端把字符处理完后,将真正的内容都整进数据库里,然后到数据库里编辑各种统计的业务逻辑,给前端调用,大致就这么个方式吧。只不过这样一来,跨数据库平台就不太好跨了。算了,反正也就我自己用用,不跨也不要紧。SQLite不知道支不支持存储过程,要足够强大的话就用它;要是不行的话就用PostgreSQL。 Oracle虽然好并且我熟悉,但是Gentoo上安装会有麻烦。

前端的输入字符处理会是个难点,具体怎么实现我还得好好想想……

 

 

修改PLSQL.vim

 

手头一大批PLSQL DEVELOPER生成的“.sql”结尾的文件。直接用VIM打开的话,会采用某种SQL的代码高亮,我不知道是哪种,反正不是PLSQL,不能识别 replace 等关键字。每次都手动输入 :set ft=plsql的话,太麻烦了。所以我想修改为默认以 PLSQL 的模式来高亮 .sql 结尾的文件。
要实现这一点,倒也挺简单。查看“filetype.vim”文件,可以看到这一段:
 
" SQL
au BufNewFile,BufRead *.sql call s:SQL()

func! s:SQL()
  if exists("g:filetype_sql")
    exe "setf " . g:filetype_sql
  else
    setf sql
  endif
endfunc
 
可以发现,关键在于 g:filetype_sql 这个变量里。于是直接在 VIMRC 中写入 let g:filetype_sql="plsql", 然后再打开 .sql 的文件,果然地,已经按 PLSQL 模式来高亮了。
 
但是还有一些问题存在着。我的文件并非我手写而成,大部分是程序生成的,里面有不少 “PROMPT xxxx” 之类的东西,以及各种排版后的语句分行。“PROMPT xxx”这句最后的分号被原有的PLSQL高亮模式识别为错误符号而标红,并连累它底下的大片代码中的分号都被标红。至于排版导致的问题则让它把一个分成几行写的PLSQL String Literal给当成错误了,不该高亮的时候高亮,该高亮的时候不高亮,还标红,很明显,它只认一行之内的。
要解决这个问题,不得不修改 PLSQL.VIM了,这个文件在Syntax文件夹内。对于“PROMPT xxx”的解决思路,我是打算把它当成注释来处理。原有的注释基本上是这样写的:
" Various types of comments.
if exists("c_comment_strings")
  syntax match plsqlCommentSkip contained "^\s*\*\($\|\s\+\)"
  syntax region plsqlCommentString contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=plsqlCommentSkip
  syntax region plsqlComment2String contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end="$"
  syntax region plsqlCommentL start="--" skip="\\$" end="$" keepend contains=@plsqlCommentGroup,plsqlComment2String,plsqlCharLiteral,plsqlBooleanLiteral,plsqlNumbersCom,plsqlSpaceError
  syntax region plsqlComment start="/\*" end="\*/" contains=@plsqlCommentGroup,plsqlComment2String,plsqlCharLiteral,plsqlBooleanLiteral,plsqlNumbersCom,plsqlSpaceError
else
  syntax region plsqlCommentL start="--" skip="\\$" end="$" keepend contains=@plsqlCommentGroup,plsqlSpaceError
  syntax region plsqlComment start="/\*" end="\*/" contains=@plsqlCommentGroup,plsqlSpaceError
endif

syn sync ccomment plsqlComment
syn sync ccomment plsqlCommentL
 
为了区别于原有的注释,我于是果断新建了一个注释组,加入
syntax region plsqlCommentLP start="PROMPT" skip="\\$" end="$" keepend contains=@plsqlCommentGroup,plsqlSpaceError

syn sync ccoment plsqlCommentLP
 
并在渲染的时候,另行指定了一个颜色:
HiLink plsqlCommentLP Operator
 
而对于String Literal,我没有看明白为何它原本无法识别多行,它原本采用的是一个正则表达式:
syn match   plsqlStringLiteral  "'\([^']\|''\)*'"
并没有不能跨行的限制,或者不跨行是VIM正则的内嵌机制?
 
解决办法倒不难,参考注释的写法,拿来直接用就是了:
syn region plsqlStringLiteral start="'" end="'"
 
无效化原来的那句后,保存。打开一份“.sql”文件,全部正常了。

原来function里可以DML的

一直以为function里面是不能做除了Select之外的DML的,除了自治事务,并将其当作与Procedure的主要区别。这个从道理上也是讲的通的,因为function应当具有被多次执行而结果一致的特点,倘若做了insert,delete,update之类的事情,每次执行结果必然不同。因此,我坚信不移了。

没想到,今天在查阅同事写的已有的系统模块时,发现他的大量function都是带着Insert,update等操作的,并且还有OUT类型的参数!与procedure的唯一区别仅仅在于多了个return的值。当时我就疑问了,这执行不报错吗?我想顺手写个语句测试下,却发现带有out类型参数的,我都没法直接写SQL。于是乎,我自己另行写了个:

CREATE FUNCTION insert_new( new_val IN NUMBER) RETURN NUMBER

IS

BEGIN

  INSERT INTO testtable(col) VALUES( new_val);

  return 1;

END insert_new;

然后用SQL调用:

 SELECT insert_new(1) FROM DUAL;

如我所料,报错了,说不能执行这类DML云云。

带着我的疑问,去找同事询问。他表示,可以执行啊。然后边说边打开了一个PLSQL DEVELOPER的Test Window,输入几个参数,然后点击执行,居然果真成功执行了。

仔细观察了两个结果,最后终于发现了不同点。Test Window所用的是一个PLSQL Block,用了赋值语句来接收函数值。我仔细查了查书,发现书上原来写的也很清楚,长期以来我所坚信的那些限制都只是“在SQL中调用自定义函数”的限制,在PLSQL Block中并不适用。

好多误区

为了准备面试,好好地恶补了一下PLSQL,连带着Oracle的一些机制。对于过去遗留的问题,也详细查找实验了一番,结果发现好多误区和讹传。可能那些说法在刚出来的时候是对的吧,但是随着版本的发展,很多早就已经不适用了。可惜网络上还是充斥着这些内容。有些是过去的遗留,还有很多是听信了那些过时结论又没实验,而却当作“答案”新近告诉别人的,这种影响极为恶劣。一看日期,人家都还以为现在这个时代依然如此呢,相当容易误导。

 

首先先说一个常见的关于复合索引的认识。很多地方关于复合索引都有这么种说法:复合索引按建立时排的顺序排在最前面的是引导列,当查询条件是引导列在最前时,走索引,否则不走;如果多个复合索引列在查询条件中顺序乱了也不走;如果中间跳过一个,我看到两种说法,一种说不走,一种说可以跳跃着走索引。

这样描述可能不清楚,举个实际例子:

CREATE TABLE tb( a number, b number, c number);

CREATE INDEX idx ON tb(a,b,c);

以上说法认为:

Read more

几个面试题

本来今天去面试动机就不纯,基本只是为了积累经验锻炼队伍去的,所以答得怎么样都无所谓了。不过第一眼看到笔试卷的时候,还是很庆幸:遇到简单题了。想象中的关于数据库各种机制的深刻挖掘基本没有,一些复杂类型的复杂用法也没有。总共12道题目,做完后感觉良好,有80%把握能对,不过现在回想一下,还是有不少题目答错了,或者答得不够好。

这笔试卷上来是几道我事后查了一下所谓的华为的面试题。

题:什么是事务?

这个要说我不知道什么是事务那真叫冤枉。但让我写,我却想不起来怎么个写法。最后只能走曲线,表示一次rollback/commit/rollback to savepoint到一次rollback/commit/rollback to savepoint 之间的那部分就是一个事务。事后查了下,原来这题的得分点在ACID上…… 原子性,一致性,隔离性,持久性。

 

Read more

整理一下Gentoo上让Mplayer在framebuffer中运行的设置过程

这两天一直在折腾。现在还在emerge kde-meta。这次基本是死磕状态,各种问题遇到一个解决一个,不留隐患。

要让mplayer能在framebuffer中运行,那么首先需要打开framebuffer。不知道该不该用“打开”这个词,反正就那个意思了。即便不准备在framebuffer中跑mplayer,只要没装X之类的东西,framebuffer也是很有必要开启的,因为原生的字体太大了,很多目录单纯ls一下都能超过屏幕边界,不得不再在后面加上 | less,可是这样一来颜色又没了。

打开framebuffer的话,主要就是编译内核,使之支持framebuffer。这部分昨天做的时候走了不少歪路,但最终发现还是应当按着Gentoo Wiki 上的相关说明 来做是最好的。

一开始是在内核中开启 “Support for frame buffer devices”,并启用下面的 firmware EDID

 

Device Drivers ->
	Graphics support  --->
		-*- Support for frame buffer devices  --->
			[*]   Enable firmware EDID
			...
			*** Frame buffer hardware drivers ***

然后选择要开的framebuffer的类型。“类型”这个词可能也不准确,应该说不同的驱动吧。昨天走的歪路就在这里。因为我顺手点进了KMS下的设置,而上面说,应当禁用掉Frame buffer hardware drivers中所列的所有驱动,不然会有冲突。事实上我用的是nvidia的闭源驱动,根本不关KMS的事。

Read more

移动(cmpp协议)发送即显短信的设置

即显短信,也就是直接在手机屏幕上显示出来,不用自己点进去查看,同时看完之后直接就没了,不会留下短信记录的那种短信。在中国移动采用的SP与ISMG之间的CMPP协议中,发送消息使用的是CMPP_SUBMIT消息,该消息的消息体如下:

 

Read more

一个简单的改名备份脚本

虽然说打算在服务器上用版本控制来管理部署的程序了,但一时终归还没用起来。而按照惯例,上传新版时旧版是不删的,仅仅改个名字存放起来而已。改名字时也没啥严格规定,一直以来有点乱。当然也许别人重命名还是比较规矩的,但反正我是很随心所欲的,搞得经常自己也记不清楚,只能靠修改时间来辨认。上次写了个脚本,把给名字自动加上时间后缀作为备份命令,倒也还管用。这次想再改进一下,上点参数,能整成 "*.latest", "*.current",  "*.last" 之类的效果。

#!/bin/bash

case "$1" in 
	"") echo "Usage: bak [option] filename"
	    echo "bak: rename a file as a backup"
	    echo "Try \"bak -h\" for help"
	    exit
            ;;
	*)
	   rename=0
	   option=0
	   while getopts "hrlc" flag
   	   do 
		option=1
		case "$flag" in
			"h") helplist=1;;
			"r") let "rename += 1";;
			"l") last=1;;
			"c") current=1;;
		esac
				
	   done
	   if [ "$option" -ne 1 ]
		then
		  filename=$1
		  newfilename=$filename.`date +%Y%m%d%H%M`
		  mv -f $filename $newfilename
		  echo $newfilename
		  exit
	   fi
		;;
esac

if [ "$helplist" = 1 ]; then
	echo "bak: rename a file as a backup"
	echo "Usage: bak [option] filename"
	echo "default(no option): rename filename to filename.`date +%Y%m%d%H%M`"
	echo "Options:"
	echo "	-l:	rename filename to filename.last"
	echo "	-c:	rename filename to filename.current"
	echo "	-r:	cut the end of filename from the last dot, example:"
	echo "			filename.last  --> filename"
	echo "multiple r will try to cut multiple part split by dot from the end, as:"
	echo "		-rrr	filename.section1.secion2.section3 --> filename"
	exit
fi
	
case "$2" in
	"") echo "Usage: bak [option] filename"
	    echo "bak: rename a file as a backup"
	    echo "Try \"bak -h\" for help"
	    ;;
	*)
	   filename=$2	
	   newfilename=$filename
	   if [ "$rename" -ne 0 ]; then
		for i in `seq 1 $rename`
  		  do
			newfilename=${newfilename%.*}
		  done
	   fi
	   if [ "$last" = 1 ]; then
		newfilename=$newfilename.last
	   elif [ "$current" = 1 ];then
		newfilename=$newfilename.current
	   else
		newfilename=$newfilename.`date +%Y%m%d%H%M`
	   fi
	   mv $filename $newfilename
	   echo $newfilename
	   ;;
esac