2015年3月26日星期四

CRL之解析lambda实现group - hubro

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
CRL之解析lambda实现group - hubro  阅读原文»

先看一个简单的group语句

select BarCode,ProductName,COUNT(BarCode) as total from ProductData where id>0 group by BarCode,ProductName
order by COUNT(BarCode) desc

  结果

BarCode ProductName total
------------------------------ ------------------------------ -----------
1212122 product2 4
21312313 product3 2

  group语法分解为

  • 查询哪些字段 BarCode,ProductName,COUNT(BarCode) as total
  • 按哪些字段进行分组 group by BarCode,ProductName
  • 按什么排序 order by COUNT(BarCode) desc

linq to sql 表示为

from p in ProductData
group p.BarCode by p.ProductName into g
select new
{g.BarCode,
g.ProductName,
total=g.Count()}

linq to sql很容易表达,用lambda该如何表达呢 

跟普通SQL查询不同,查询字段和排序可用聚合函数count,sum,抛开这,用lambda,同样的查询可表示为

这里用匿名对象来作选择器

query.Select(b=>new{b.BarCode,b.ProductName})

.Where(b=>b.Id>0)

.GroupBy(b=>new{b.BarCode,b.ProductName})

.OrderBy(b=>b.BarCode,true);
query.Select(b=>new{b.BarCode,b.ProductName}) 能表示 select BarCode,ProductName 但匿名对象可没Count(b.ProductName)这样的语法,所以没法生成select count(BarCode)这样的语法
没有直接的方法,但是有间接的方法,扩展方法
扩展方法真是个好东西,解决了很多问题
定义一个扩展方法,名称定义为大写,为避免冲突
public static int COUNT(this object origin)
{
return 0;
}

  所有object对象将会有COUNT()方法

将上面语法进行改进为

query.Select(b=>new{b.BarCode,b.ProductName,total=b.BarCode.COUNT()})

  以这样形式进行表示,这样在语法上是编译通过的,并且lambda支持这样的解析

完整表示为

query.Select(b=>new{b.BarCode,b.ProductName,total=b.BarCode.COUNT()})

.Where(b=>b.Id>0)

.GroupBy(b=>new{b.BarCode,b.ProductName})

.OrderBy(b=>b.BarCode.COUNT(),true);

  这样,完整的group表示语法就完成了,致少在逻辑上,是能实现SQL的group语法了,剩下就需要进行解析了

lambda解析比较麻烦,这里就简单演示,回头再写篇详细讲讲

//此方法解析方法调用表达式的属性名和方法名
string GetPropertyMethod(Expression item,out string methodName)
{
        //转换为方法表达式
var method = item as MethodCallExpression;
MemberExpression memberExpression;
//获取访问属性表达式
if (method.Arguments[0] is UnaryExpression)
{
memberExpression = (method.Arguments[0] as UnaryExpression).Operand as MemberExpression;
}
else
{
memberExpression = method.Arguments[0] as MemberExpression;
}
methodName = method.Method.Name;//调用的方法名
return memberExpression.Member.Name;//返回访问的属性名
}
解析Select

public LambdaQuery<T> Select<TResult>(Expression<Func<T, TResult>> resultSelector)
{
      string QueryFullName;
var newExpression=resultSelector.Body as NewExpression;//转换为匿名对象表达式
        int i=0;
foreach (var item in newExpression.Arguments)//遍历所有参数
{
var memberName = newExpression.Members.Name;//获取构造的属性名
if (item is MethodCallExpression)//如果是方法
{
string methodName;
string propertyName = GetPropertyMethod(item,out methodName);//获取方法名和属性名
QueryFullName = string.Format("{0}({1}) as {2}", methodName, propertyName , memberName);
}
else//直接属性
{
var memberExpression = item as MemberExpression;//转换为属性访问表达式
QueryFullName = memberExpression.Member.Name;//返回属性名
}
        i+=1;
}
return this;
}

 QueryFullName即为查询字段语法

 解析OrderBy,过程和上面差不多

public LambdaQuery<T> OrderBy<TKey>(Expression<Func<T, TKey>> expression, bool desc = true)
{
       string QueryOrderBy;
string name;
if (expression.Body is MethodCallExpression)//如果是方法
{
string methodName;
string propertyName = GetPropertyMethod(expression.Body, out methodName);
name = string.Format("{1}({0})", propertyName, methodName);
QueryOrderBy += string.Format(" {0} {1}", name, desc ? "desc" : "asc");
}
else
{
MemberExpression mExp = (MemberExpression)expression.Body;
if (!string.IsNullOrEmpty(QueryOrderBy))
{
QueryOrderBy += ",";
}
name = mExp.Member.Name;
QueryOrderBy += string.Format(" {0} {1}", name, desc ? "desc" : "asc");
}
return this;
}

  QueryOrderBy即为排序语法

经过若干处理,此处省略1万字

最终结果为

//using CRL以获取扩展方法
var query = Code.ProductDataManage.Instance.GetLamadaQuery();
query.Page(15, 1);
query.Where(b => b.Id > 0);
int count;
//选择GROUP字段
query.Select(b => new
{
b.BarCode,
b.ProductName,
total = b.BarCode.COUNT(),//等效为count(BarCode) as total
sum1 = b.Number.SUM()//等效为sum(Number) as sum1
});
//GROUP条件
query.GroupBy(b => new { b.BarCode, b.ProductName });
//设置排序
query.OrderBy(b => b.BarCode.Count(), true);//等效为 order by count(BarCode) desc
var list = Code.ProductDataManage.Instance.AutoSpGroupPage(query, out count);

foreach (dynamic item in list)
{
var str = string.Format("{0}______{1} {2} {3}<br>", item.BarCode, item.ProductName, item.total, item.sum1);//动态对象
Response.Write(str);
}

当然也可以加上HAVING语法,这个比较麻烦,在解析二元运算时还得按这样解析扩展方法,稍后实现


本文链接:CRL之解析lambda实现group,转载请注明。

net-force.nl/Programming writeup - KAlO2  阅读原文»

  从 wechall.netnet-force.nl 网站,发现网站的内容不错,里面也有不同类型的挑战题目:Javascript / Java Applets / Cryptography / Exploits / Cracking / Programming / Internet / Steganography,有的还有一定的难度。注册了帐号做题,我也从中学到了不少知识。对网络攻防有兴趣的同学可以尝试下。

level 601: Keep walking...
/*
This is a challenge to test your basic programming skills.

Pseudo code:
Set X = 1
Set Y = 1
Set previous answer = 1

answer = X * Y + previous answer + 3

After that => X + 1 and Y + 1 ('answer' becomes 'previous answer') and repeat this till you have X = 525.

The final answer is the value of 'answer' when X = 525. Fill it in below to check if it's the correct answer. If it is, you will get the password for the challenge page.
*/
第一题是热身题,直接按照题目所说的写代码就行了。

#include <stdio.h>

int main()
{
int answer = 1;
for(int x = 1, y = 1; x<=525; ++x, ++y)
answer
+= (x*y + 3);
printf(
"answer: %d\n", answer);

return 0;
}

level 602: Are you fast enough?
/*
This challenge is a simple calculation.
When you click on the link below you will get a number.
The calculation is: answer = (number * 3 + 2) - 250

Example with number 1500:
4252 = (1500 * 3 + 2) - 250

In this example 4252 is the answer...answer like this: prog2.php?solution=4252
You must do this within 2 seconds. If the answer is correct, you will get the password.
Get a number.
https://net-force.nl/challenge/level602/prog2.php
*/
限时2秒,手动计算再发送肯定是来不及的。不变的信息先构造好,添加动态信息马上发出去。
春节回家需要网上买火车票,比别人晚半秒钟下手可能就没票了,所以那些车次,时间,身份证等信息需要事先填写好再刷票。
javascript 是浏览器用的语言,于是在 Chrome 浏览器的控制台(按 F12 键或 Ctrl + Shift + J 唤出)粘贴以下代码运行。
javascript 直接用 XMLHttpRequest 构造 HTTP 请求。

var url = 'https://net-force.nl/challenge/level602/prog2.php';
var req = new XMLHttpRequest();
req.open(
'GET', url, false/*asynchronous*/);
// req.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
//
req.send(message);
req.send(null);
if(req.status == 200)
{
var text = req.responseText;
var number = parseInt(text.split("'", 2)[1]);
answer
= (number * 3 + 2) - 250;

var url_answer = url + '?solution=' + answer;
req.open(
'GET', url_answer, false/*asynchronous*/);
req.send(
null);
console.log(req.responseText);
}

上面的 url 写错了,比如多加了 www. 或者写成了 http 协议,服务器可能会返回以下错误。
XMLHttpRequest cannot load https://www.net-force.nl/challenge/level602/prog2.php. Origin https://net-force.nl is not allowed by Access-Control-Allow-Origin.
这个是 Javascript 的同源策略(Same Origin Policy),是由 Netscape 公司提出的一个安全策略。

请求返回的内容如下,除了数字很可能不同。
<p>You will need this number '8616'.</p>
<i>Answer like this: prog2.php?solution=12345</i><br>
我们可以用'作为分割符,得到我们要的数字,找到第二个就不用接着找下去了。代码为:text.split("'", 2)[1]
这种做法我在读 sqlmap 的代码 sqlmap/lib/utils/versioncheck.py 的时候看到过,它用空格作为分隔符获取 Python 的版本字符串。

level 603: Wanna play?!?!

/*

You have 5 balls that you have to divide (put the balls in the cups) between a number of cups in all possible ways.

1 cup:
---
|5|
---
1 possibility

Total: 1 possibility

2 cups:
-----
|1|4|
-----
|2|3|
-----
|3|2|
-----
|4|1|
-----
|5|0|
-----
|0|5|
-----
6 possibilities

Total: 7 possibilities

3 cups:
21 possibilities
Total: 28 possibilities

Continue until you have 500 cups. The total of possibilities from 1 to 500 is the answer.

*/

排列组合问题
5个球放N个杯子的放法有多少中,转换成数学语言描述:
x1+x2+...+xn = 5, x1~xn 均为0或正整数。求方程解的个数。
(x1+1)+(x2+1)+...+(xn+1) = 5 + n
于是等价于
x1+x2+...+xn = n+5, x1~xn 均为正整数,方程解的个数。
x1与x2互换属于不同的解,所以是排列问题而非组合问题。
n+5个杯子排成一列,中间用n-1个栏板隔开,所以答案是 C(n+5, n-1)
因为 C(m, n) = C(m, m-n),所以 C(n+5, n-1) = C(n+5, 6)
我们验证一下,
1个杯子: C(6,6)=1
2个杯子: C(7,6)=C(7,1)=7
3个杯子: C(8,6)=C(8,2)=(8*7)/(1*2)=28
与例子保持吻合,以此类推
500个杯子就是 C(505,6)=505*504*503*502*501*500/6!

#include <stdio.h>
#include
<inttypes.h>

int main()
{
int64_t cups
= 500;
int64_t answer
= cups*(cups+1)*(cups+2)*(cups+3)*(cups+4)*(cups+5)/(阅读更多内容

没有评论:

发表评论