Powerful Batch (4) Using Array
Batch commands doesn't support array, but it doesn't mean we can't simulate it.
Let's see the following code:
1 2 3 4 5 6 7 | SET Obj_Length=2 SET Obj[0].Name=Test1 SET Obj[0].Value=Hello World SET Obj[1].Name=Test2 SET Obj[1].Value=blahblah |
We defined an array of a struct in the code above.
When accessing the value of an array element, we can do something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | SET Obj_Index=0 :LoopStart IF %Obj_Index% EQU %Obj_Length% GOTO :EOF SET Obj_Current.Name=0 SET Obj_Current.Value=0 FOR /F "usebackq delims==. tokens=1-3" %%I IN (`SET Obj[%Obj_Index%]`) DO ( SET Obj_Current.%%J=%%K ) ECHO Name = %Obj_Current.Name% ECHO Value = %Obj_Current.Value% ECHO. SET /A Obj_Index=%Obj_Index% + 1 GOTO LoopStart |
Output:
Name = Test1
Value = Hello World
Name = Test2
Value = blahblah
Very cool, huh~~
Verbatim identifier: Declaring variables with prefix ‘@’ in C#
In C#, '@' is not only a prefix for string literal to not escape the string, but can be used as a prefix of variable name as well, which is called 'verbatim identifier'. See the code below:
1 2 3 4 5 6 7 8 9 | class @class { public static void @static(bool @bool) { if (@bool) System.Console.WriteLine("true"); else System.Console.WriteLine("false"); } } |
There are 3 names, @class, @static and @bool, declared with '@'. There will be a complilation error without the '@' since those names for keywords, but '@' makes the compiler happy. '@' can also be prefix for normal names, such as:
1 2 3 4 | static void Test(string @str) { Console.WriteLine(str); } |
In this case, '@' has no effect. @str is equlvalent to str.
Anyway, according to C# spcification, " Use of the @ prefix for identifiers that are not keywords is permitted, but strongly discouraged as a matter of style."
Powerful Batch (3) Check if the directory is in %Path%
It seems there is not a perfect way to do it. The only way I found is to split %Path% by semicolon and then compare every part with the input.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | :InPath [In]Path [Out]0/1 SETLOCAL SET LocalPathCopy=%PATH% SET Result=0 :WHILE IF "%LocalPathCopy%" == "" GOTO WEND FOR /F "delims=;" %%I IN ("%LocalPathCopy%") DO ( IF /I "%%~I" == "%~1" ( SET Result=1 GOTO WEND ) ) FOR /F "delims=; tokens=1,*" %%I IN ("%LocalPathCopy%") DO ( SET LocalPathCopy=%%~J ) GOTO WHILE :WEND :InPathRet ENDLOCAL & SET %2=%Result% & GOTO :EOF |
Sample Usage:
1 2 3 | SET x=C:\Windows Call :InPath %x% Result IF %Result% == 0 SET Path=%Path%;%x% |
Start elevated application in command prompt
After UAC is introduced in Vista, application can run with or without administrator privilege. It is confusing that some old application fails on Vista. The solution may be to right click on the file and "Run as administrator". This is a tradeoff for security. But what if there is no "right click", for example, in a command prompt. In this case, you have to start another command prompt with administrator, go to the directory again and run the application. Oh no...
There is a simple solution. Save the script below as Elevate.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var command = WScript.Arguments.Item(0); var argument = ""; for (var i = 0; i < WScript.Arguments.Count(); ++i){ argument += WScript.Arguments.Item(i) + " "; } try{ var shellapp = new ActiveXObject("Shell.Application"); shellapp.ShellExecute(command, argument, null, "runas", 1); } catch(e){ WScript.Echo("Something wrong: " + e.description); } |
When it is necessary to run an application with elevation, just type "Elevate <exefile> <arguments>", i.e., "Elevate cmd /k"
BTW, the UAC dialog will pop up for sure. You still need to click on the "Yes" button.
Powerful Batch (2) Fibonacci Function
So powerful...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | @ECHO OFF SETLOCAL SET X=10 CALL :Fib %X% Y ECHO Fib^(%X%^)=%Y% GOTO :EOF :Fib [In]X [Out]Result SETLOCAL SET A=%1 SET D=1 SET E=0 IF %A% LEQ 1 ( GOTO FibRet ) SET /A B=%A%-1 SET /A C=%A%-2 CALL :Fib %B% D CALL :Fib %C% E :FibRet ENDLOCAL & SET /A %2=%D%+%E% & GOTO :EOF |
Output is“Fib(10)=89”
Powerful Batch (1) String Truncation
Get current hour:
1 2 3 4 5 6 7 8 9 | @ECHO OFF SET Hour=%TIME:~0,2% IF %Hour% GTR 12 ( ECHO Afternoon ) ELSE ( ECHO Morning ) |
Print Windows version:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @ECHO OFF FOR /F "tokens=1,2,3,4" %%I IN ('VER') DO ( SET Ver_Temp=%%L ) SET Ver_Major=%Ver_Temp:~0,1% SET Ver_Minor=%Ver_Temp:~2,1% SET Ver_Build=%Ver_Temp:~-5,4% ECHO Windows Version: ECHO Major %Ver_Major% ECHO Major %Ver_Minor% ECHO Build %Ver_Build% |
Overload equality operator in C#
运算符重载一直是一个很诡异事情,因为在写代码的时候,不知道某个运算符有没有被重载过。在C++里面,运算符重载可以写在类的外面,当intellisense不工作的时候,找到一个运算符的重载函数是一件相当头疼的事情。这个问题在C#中改善了不少,因为运算符重载一定要写在类内,而且intellisense很强大。不过另一个问题又产生了……
先来看C++中的“==”重载:
1 2 3 4 5 6 7 8 9 | struct A{ int x; int y; }; inline bool operator == (const A& a, const A& b){ return a.x == b.x && a.y == b.y; } |
上面这段代码中,由于声明的关系,a和b永远不可能为NULL,所以直接调用a.x和b.x是没有问题的。
而在C#中:
1 2 3 4 5 6 7 8 9 10 11 12 | struct A { public int x, y; public static bool operator ==(A a, A b) { return a.x == b.x && a.y == b.y; } public static bool operator !=(A a, A b) { return !(a == b); } } |
这段代码是没问题的,因为A是struct,而struct不可能为null。但换成class就有问题了,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class A { public int x, y; public static bool operator ==(A a, A b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } return a.x == b.x && a.y == b.y; } public static bool operator !=(A a, A b) { return !(a == b); } } |
由于reference type可以为null,所以要先检查a和b是不是null,但是“a == null”这一句又会去调用“operator ==”,于是就无限递归下去了……想了很久都没想出来变通的方法,而且System.String的实现也很诡异:
1 2 3 4 5 6 7 8 | public static bool operator ==(string a, string b) { return Equals(a, b); } public static bool Equals(string a, string b) { return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b))); } |
看上去也会无限递归的(Reflector出来的,不一定准),很神奇……
虽然对于Referece type不建议重载==,但是不建议并不代表不能用吧,这个设计太挫了……
Javascript学习心得
这几天做Ajax,顺便研究了一下Javascript,发现以前对Javascript是完全不了解=.=
总结如下(以下简称Js):
1、Js中没有Class,只有Function,一个Function可以看成一个类的构造函数,new Function即new Class。每个Function有一个对象prototype,new Function的时候,自动把这个Function的prototype复制到新的对象中。
2、Function中可以使用this关键字,指代的是包含这个Function的类,不过this是动态绑定的,比如
1 2 3 4 5 6 7 8 9 10 11 | var x = { value:"x", a:function(){ alert(this.value); } }; var y = { value:"y", a:x.a }; y.a(); |
运行结果是y。这种模式在Lua中见过,如果要让运行结果是x,要对x.a做一个Binder,显示指定this为x,并调用a.x.apply(obj, ...)。
3、Js中没有继承,要实现继承的功能,有N种比较猥琐的方法。一种是在新的对象中放一个base指针,指向它的父类。还有一种是复制prototype。不过看上去都很恶心。以前看过Lua中有一种继承的方法是做一个索引表,调用函数的时候查找它父类的函数,不过Js不支持运算符重载=.=
4、Js中唯一的网络组件是XMLHttpRequest,在IE7和Firefox 中可用,IE6要用new ActiveXObject("Msxml2.XMLHTTP")。XMLHttpRequest可以产生一个异步通讯的线程,是Ajax的主要工具之一。线程的管理依赖于浏览器,具体的说明可以看Ray的一篇文章。
5、Js中数值0等价于false,也就是if (0){}等价于if (false){},在写Array.Contains的时候总算明白了为什么Lua中0不等价于false,因为Array.Contains可以返回null表示没有找到,而调用的时候可以写If (obj.Contains(val)){},而不用写if (obj.Contains(val)!=null){},但是Js中就只有写后一种了=.=
6、Js中有delete关键字,但不是用来进行垃圾回收的,只能用来在类中删除一个元素。垃圾回收是自动的。
7、Js中有很多保留字(因为ECMA规范的缘故),比如class,IE7会认为var class=0是错误而停止执行。
8、Firefox中的String重载了[]运算符,等价于charAt,但这不是标准。
9、Js和Java同宗,N多相似的地方,比如Date中月份从0开始,0表示一月;String是不可变类;函数的命名和Java几乎完全相同。
10、Firefox下不允许修改Object.prototype,而IE下可以。
先写到这,以后再补……