[转载]PHP支付宝手机支付 接口 - 小窗口的浪漫 - 博客园

mikel阅读(1378)

[转载]支付宝手机支付 接口 – 小窗口的浪漫 – 博客园.

讲解:

一:取得  token

 

要取得 token 有两个 参数是 是必须

 

req_data  和 sign

req_data格式如下(这是一些必填的。如果想要更多的参数自己去下载手册):

<direct_trade_create_req>
<notify_url>{通知地址}
<call_back_url>{返回地址}
<seller_account_name>{商家支付宝账号}
<out_trade_no>{外部订单号}
{商品介绍}
<total_fee>{商品价格}

sign(签名)格式如下

$params = array(
/* 基本信息 */
'partner' => {支付宝pid},
'req_id' => md5({网站订单号}),
'service' => 'alipay.wap.trade.create.direct',
'format' => 'xml',
'v' => '2.0',
'sec_id' => 'MD5',
"_input_charset" => CHARSET
"req_data" => {以面的req_data}
);

if($sort){
/* 排序 */
ksort($params);
reset($params);
}
$sign = '';
foreach ($params AS $key => $value)
{
$sign .= "{$key}={$value}&";
}

md5(substr($sign, 0, -1) . {支付宝key});

sign 要注意的地方 是 排序 md5之前一定要按手册上的排序不然会出错的

然后以post方式提交给

http://wappaygw.alipay.com/service/rest.htm?

注意 返回的 数据是 经过 urlencode 的 所心我们要用 urldecode 解码 然后还得用解析 返回的数据

/**
	 * 解析远程模拟提交后返回的信息
		 * @param $str_text 要解析的字符串
	 * @return 解析结果
	 */
	function parseResponse($str_text) {
		//以“&”字符切割字符串
		$para_split = explode('&',$str_text);
		//把切割后的字符串数组变成变量与数值组合的数组
		foreach ($para_split as $item) {
			//获得第一个=字符的位置
			$nPos = strpos($item,'=');
			//获得字符串长度
			$nLen = strlen($item);
			//获得变量名
			$key = substr($item,0,$nPos);
			//获得数值
			$value = substr($item,$nPos+1,$nLen-$nPos-1);
			//放入数组中
			$para_text[$key] = $value;
		}
		
		if( ! empty ($para_text['res_data'])) {			
			//token从res_data中解析出来(也就是说res_data中已经包含token的内容)
			$doc = new DOMDocument();
			$doc->loadXML($para_text['res_data']);
			$para_text['request_token'] = $doc->getElementsByTagName( "request_token" )->item(0)->nodeValue;
		}
		
		return $para_text;
	}

最后的 规范的支付表单数据 就是(这里是要用get)

$params = array(
            'partner'           => $this->_config['wap_alipay_partner'],
            'req_id'            =>  md5({网站订单号}),
            'service'           =>  'alipay.wap.trade.create.direct',
            'format'            =>  'xml',
            'v'                 =>  '2.0',   
            'sec_id'            =>  'MD5',
            "_input_charset"    => CHARSET
			'req_data'=>'<auth_and_execute_req><request_token>' . {token} . '</request_token></auth_and_execute_req>',
			'service'	=>	"alipay.wap.auth.authAndExecute",			
		
	);
	//这个地方也要签名的。方式和上面一样
	$params['sign']	= _get_sign($params);
	
	//get数据
	$return = array(
		'online'    =>  {联线},
		'desc'      =>  {支付说明},
		'method'    =>  'GET',
		'gateway'   =>  'http://wappaygw.alipay.com/service/rest.htm?',
		'params'    =>  $params,
	)

最后 跳转到支付宝

 

 <form action="<?php echo $return['gateway'];?>" id="payform" method="<?php echo $return['method'];?>" style="display:none">
<?php foreach ( $return['params'] $_k=>$value){?>
	<input type="hidden" name="<?php echo $_k;>" value="<?php echo $value;>" />
<?php }?>

</form>
<script type="text/javascript">
  document.getElementById('payform').submit();
</script>

[转载]Fatal error: Call to undefined function openssl_pkey_get_private() - wust_star的专栏 - 博客频道 - CSDN.NET

mikel阅读(1685)

[转载]Fatal error: Call to undefined function openssl_pkey_get_private() – wust_star的专栏 – 博客频道 – CSDN.NET.

在windows系统中IIS环境的操作方式: 

1、在php.ini中 
extension=php_openssl.dll去掉前面的注释 
2、复制php安装目录中的: 
libeay32.dll 
ssleay32.dll 
至c:\windows\system32 
3、复制php_openssl.dll至c:\windows\system32 
4、重启IIS 

---AppServ Win32如何打开openssl--------------------1.打开c:/windows,里面有一个php.ini文件(AppServ居然将php的配置文件移到这里来!),然后在里面搜索 ;extension=php_openssl.dll ,把前面的逗号去掉。

2.进入AppServ的安装目录,到php文件夹里面,分别搜索 libeay32.dll 和 ssleay32.dll ,把它们复制到 c:/windows/system32 下面

3.重新启动 Apache,就可以了,至于phpMailer的使用方法,请参考phpMailer的例子。

[转载]云图如何制作附近实体店的地图?-微信微博支付宝 - 酸奶小妹 - 博客园

mikel阅读(1245)

[转载]【云图】如何制作附近实体店的地图?-微信微博支付宝 – 酸奶小妹 – 博客园.

摘要:

附近连锁店地图与全国连锁店地图,最大的区别就是:

1、附近连锁店地图需要先定位,然后搜索附近的店铺。

2、全国连锁店地图,是先选择城市,然后检索某城市内的全部门店信息。

本文就详细讲解了如何制作附近实体店的地图,并调起高德地图进行导航,调起打电话功能。

本文还详细讲解了如何设置支付宝服务、微信公众号、微博官方账号的地图功能。

————————————————————————

 

一、支付宝设置

登录支付宝服务窗:https://fuwu.alipay.com/platform/queryMenu.htm

自定义菜单 -> 主菜单 -> 有子级菜单

填写子菜单名称,设置为跳转网页,并且放入网址。比如菜鸟物流:http://zhaoziang.com/amap/cainiao.html

最后点击发布。

 

二、微信设置

登录微信公众平台:https://mp.weixin.qq.com

功能->高级功能->编辑模式->自定义菜单-> 菜单管理->添加->设置动作

设置为跳转网页,并且放入网址。比如菜鸟物流:http://zhaoziang.com/amap/cainiao.html

最后点保存。

 

三、微博设置

登录微博:http://weibo.com/

管理中心->粉丝服务->高级功能->编辑模式->自定义菜单-> 菜单管理->添加->设置动作

设置为跳转网页,并且放入网址。比如菜鸟物流:http://zhaoziang.com/amap/cainiao.html

最后点保存。

 

四、云图设置

登录云图管理台:http://yuntu.amap.com/datamanager/index.html

新建地图

导入CSV数据。(支持UTF8和GBK 编码,数据不超过10,000 条)

 

五、代码与获取网址

将以下代码复制下来,替换key、tableID、图标,然后生成自己的网址。

获取key的地址:http://api.amap.com/key

获取tableID的地址:

进入你的云图->获取tableID

 

全部源代码:





菜鸟物流全国站点

<script src="http://webapi.amap.com/maps?v=1.2&amp;key=【您的key】" language="javascript"></script>

<div class="header clearfix"><a id="iListBtn"></a>列表模式 <a id="iMapBtn"></a>地图模式</div>

&nbsp;

&nbsp;

<div id="map" class="clearfix"></div>

&nbsp;

<div id="list" style="display: none;">正在读取数据……</div>

&nbsp;

&nbsp;

<script language="javascript">// <![CDATA[
function display(id1,id2){
    document.getElementById('map').style.display = 'none';
    document.getElementById('list').style.display = 'none';
    document.getElementById(id1).style.display = 'block';
    document.getElementById(id2).style.display = 'block';
    if (id1 === 'map' && mapObj) {
        mapObj.setFitView();
    }
}
var mapObj;
var cloudDataLayer;
var cloudSearch;
var cpoint;
//初始化地图对象,加载地图
function mapInit(){
    mapObj = new AMap.Map("map");
    mapObj.plugin('AMap.Geolocation', function () {
        geolocation = new AMap.Geolocation({
            enableHighAccuracy: true,//是否使用高精度定位,默认:true
            timeout: 10000,          //超过10秒后停止定位,默认:无穷大
            maximumAge: 0,           //定位结果缓存0毫秒,默认:0
            convert: true,           //自动偏移坐标,偏移后的坐标为高德坐标,默认:true
            showButton: true,        //显示定位按钮,默认:true
            buttonPosition: 'LB',    //定位按钮停靠位置,默认:'LB',左下角
            buttonOffset: new AMap.Pixel(10, 20),//定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
            showMarker: true,        //定位成功后在定位到的位置显示点标记,默认:true
            showCircle: false,        //定位成功后用圆圈表示定位精度范围,默认:true
            panToLocation: true,     //定位成功后将定位到的位置作为地图中心点,默认:true
            zoomToAccuracy:true      //定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
        });
        mapObj.addControl(geolocation);
        geolocation.getCurrentPosition();
        AMap.event.addListener(geolocation, 'complete', onComplete); //返回定位信息-成功
        AMap.event.addListener(geolocation, 'error', function(){
            alert('哟,定位失败啦!');
        });    //返回定位信息-失败 
    });
}
function onComplete(data) {
    var lngX = data.position.getLng();
    var latY = data.position.getLat();
    cpoint = new AMap.LngLat(lngX,latY);
    //cpoint = new AMap.LngLat(116.38298,39.955543);
    myCloudList();  
}
//云图加载列表
function myCloudList(){
    //列表
    var search; 
    var searchOptions = {
            pageSize:20
        };
    mapObj.plugin(["AMap.CloudDataSearch"], function() {
        cloudSearch = new AMap.CloudDataSearch('【您的tableID】', searchOptions); //构造云数据检索类
        AMap.event.addListener(cloudSearch, "complete", cloudSearch_CallBack); //查询成功时的回调函数
        AMap.event.addListener(cloudSearch, "error", errorInfo); //查询失败时的回调函数
        cloudSearch.searchNearBy(cpoint, 10000); //周边检索 
    });
}
var markers = new Array(); 
var windowsArr = new Array();
//添加marker和infowindow     
function addmarker(i, d){  
    var lngX = d._location.getLng();  
    var latY = d._location.getLat();  
    var IconOptions = {
        image : "cainiao.png", //您的小图标33*33
        size : new AMap.Size(33,33),
        imageSize : new AMap.Size(33,33),
        imageOffset : new AMap.Pixel(-16,0)
    };
    var myIcon = new AMap.Icon(IconOptions);
    var markerOption = {  
        map:mapObj,  
        icon: myIcon,   
        offset: new AMap.Pixel(-15,-30),   
        position:new AMap.LngLat(lngX, latY)    
    };              
    var mar = new AMap.Marker(markerOption);    
    markers.push(new AMap.LngLat(lngX, latY));  
  
    var infoWindow = new AMap.InfoWindow({  
        content: "

<h3>" + d._name + "</h3>


" + "<img style=\"width:280px;height:180px;overflow:hidden;\" src='cainiao2.png' />

地址:" + d._address + "

" + "

电话:<a href=\"tel:" + d.telephone + "\">" + d.telephone + "</a>

<a href='http://mo.amap.com/?q=" + d._location.getLat() + "," + d._location.getLng() + "&name=" + d._name + "'>到这儿去</a>

",
        size:new AMap.Size(280, 0),  
        autoMove:true,  
        offset:new AMap.Pixel(0,-30),
        closeWhenClickMap: true        
    });    
    windowsArr.push(infoWindow);     
    var aa = function(){infoWindow.open(mapObj, mar.getPosition());};    
    AMap.event.addListener(mar, "click", aa);    
}
//回调函数-成功
function cloudSearch_CallBack(data) {
    clearMap();
    var resultStr="";
    var resultArr = data.datas;
    var resultNum = resultArr.length;
    for (var i = 0; i < resultNum; i++) {
        resultStr += "

<div class=\"item\">";
        resultStr += "

<h3>" + (i+1) + "、" + resultArr[i]._name + "</h3>


";
        resultStr += "

地址:" + resultArr[i]._address + "

";
        resultStr += "

电话:<a href=\"tel:" + resultArr[i].telephone + "\">" + resultArr[i].telephone + "</a>

";
        resultStr += "

地图:<a href='http://mo.amap.com/?q=" + resultArr[i]._location.getLat() + "," + resultArr[i]._location.getLng() + "&name=" + resultArr[i]._name + "'>到这里去</a>

";
        resultStr += "</div>


";
        addmarker(i, resultArr[i]); //添加大标注
    }
    if (document.getElementById('map').style.display !== 'none') {
        mapObj.setFitView();
    }
    document.getElementById("list").innerHTML = resultStr;
}
//回调函数-失败
function errorInfo(data) {
    resultStr = data.info;
    document.getElementById("list").innerHTML = resultStr;
}
//清空地图
function clearMap(){
    mapObj.clearMap();
    document.getElementById("list").innerHTML = '正在读取数据……';
}
// ]]></script>

demo网址(请用手机浏览器查看):http://zhaoziang.com/amap/cainiao.html

 

效果图:

 

六、其他云图教程

【支付宝中的全国家乐福地图】http://www.cnblogs.com/milkmap/p/3786144.html

【微信中的全国AMF海水农场地图】http://www.cnblogs.com/milkmap/p/3780417.html

【官网中的全国AMF海水农场地图】http://www.cnblogs.com/milkmap/p/3778398.html

【应用中webview形式的全国KTV地图】http://www.cnblogs.com/milkmap/p/3765925.html

 

【三甲医院】http://www.cnblogs.com/milkmap/p/3637899.html

【东莞地图】http://www.cnblogs.com/milkmap/p/3657829.html

【贪官落马图】http://www.cnblogs.com/milkmap/p/3678377.html

 

七、从零开始学高德JS API系列教程

【地图展现】http://www.cnblogs.com/milkmap/p/3687855.html

【控件】http://www.cnblogs.com/milkmap/p/3707711.html

【覆盖物】http://www.cnblogs.com/milkmap/p/3727842.html

【搜索服务】http://www.cnblogs.com/milkmap/p/3745701.html

【路线规划】http://www.cnblogs.com/milkmap/p/3755257.html

【坐标转换】http://www.cnblogs.com/milkmap/p/3768379.html

 

[转载]Android: 用jni 获取MAC地址 - Braincol - 博客园

mikel阅读(1037)

[转载]Android: 用jni 获取MAC地址 – Braincol – 博客园.

最近有个需求,需要在jni层获取Android设备的mac地址,google了一圈,没看到现成的实现方法,所以就只好自己写一个了。

基本思路是,通过jni调用Android java层的api,获取wifi的mac地址。理论上,所有的java代码都可以翻译成jni代码,所以应该可以实现。

 

首先来看看mac地址获取的java实现代码:

public String getLocalMacAddress(Context context) {
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
}

代码相当简单。 就两个对象:WifiManager 和 WifiInfo对象,所以这个翻译成jni代码也不会有多复杂。

先在jni获取WifiManager 对象:

/*
* 获取WifiManager 对象
* 参数: jCtxObj 为Context对象
*/
jobject getWifiManagerObj(JNIEnv *env, jclass clz, jobject jCtxObj)
{
LOGI("gotWifiMangerObj ");
//获取 Context.WIFI_SERVICE 的值
//jstring jstr_wifi_serveice = env-&gt;NewStringUTF("wifi");
jclass jCtxClz= env-&gt;FindClass("android/content/Context");
jfieldID fid_wifi_service = env-&gt;GetStaticFieldID(jCtxClz,"WIFI_SERVICE","Ljava/lang/String;");
jstring jstr_wifi_serveice = (jstring)env-&gt;GetStaticObjectField(jCtxClz,fid_wifi_service);

jclass jclz = env-&gt;GetObjectClass(jCtxObj);
jmethodID mid_getSystemService = env-&gt;GetMethodID(jclz,"getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
jobject wifiManager = env-&gt;CallObjectMethod(jCtxObj,mid_getSystemService,jstr_wifi_serveice);

//因为jclass 继承自 jobject,所以需要释放;
//jfieldID、jmethodID是内存地址,这段内存也不是在我们代码中分配的,不需要我们来释放。
env-&gt;DeleteLocalRef(jCtxClz);
env-&gt;DeleteLocalRef(jclz);
env-&gt;DeleteLocalRef(jstr_wifi_serveice);

return wifiManager;
}

然后,再获取WifiInfo对象:

/*
* 获取WifiInfo 对象
* 参数: wifiMgrObj 为WifiManager对象
*/
jobject getWifiInfoObj(JNIEnv *env, jobject wifiMgrObj)
{
LOGI("getWifiInfoObj ");
if(wifiMgrObj == NULL){
return NULL;
}
jclass jclz = env-&gt;GetObjectClass(wifiMgrObj);
jmethodID mid = env-&gt;GetMethodID(jclz,"getConnectionInfo","()Landroid/net/wifi/WifiInfo;");
jobject wifiInfo = env-&gt;CallObjectMethod(wifiMgrObj,mid);

env-&gt;DeleteLocalRef(jclz);
return wifiInfo;
}

现在只差最后一步了,调用WifiInfo的getMacAddress()方法:

/*
* 获取MAC地址
* 参数:wifiInfoObj, WifiInfo的对象
*/
char* getMacAddress(JNIEnv *env, jobject wifiInfoObj)
{
LOGI("getMacAddress.... ");
if(wifiInfoObj == NULL){
return NULL;
}
jclass jclz = env-&gt;GetObjectClass(wifiInfoObj);
jmethodID mid = env-&gt;GetMethodID(jclz,"getMacAddress","()Ljava/lang/String;");
jstring jstr_mac = (jstring)env-&gt;CallObjectMethod(wifiInfoObj,mid);
if(jstr_mac == NULL){
env-&gt;DeleteLocalRef(jclz);
return NULL;
}

const char* tmp = env-&gt;GetStringUTFChars(jstr_mac, NULL);
char* mac = (char*) malloc(strlen(tmp)+1);
memcpy(mac,tmp,strlen(tmp)+1);
env-&gt;ReleaseStringUTFChars(jstr_mac, tmp);
env-&gt;DeleteLocalRef(jclz);
return mac;
}

只需要把这三个过程串起来就ok了

jobject wifiManagerObj = getWifiManagerObj(env, clz, jCtxObj);
jobject wifiInfoObj = getWifiInfoObj(env,wifiManagerObj);
char * mac = getMacAddress(env,wifiInfoObj);

完整源码为:

http://download.csdn.net/detail/niosm/4409938

[转载]Android 获取WIFI MAC地址的方法 - OPEN 开发经验库

mikel阅读(967)

[转载]Android 获取WIFI MAC地址的方法 – OPEN 开发经验库.

1. 常用方法,调用Android的API:WifiManager

 

<uses-permission Android:name=”Android.permission.ACCESS_WIFI_STATE”></uses-permission>

 

WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
 

此方法需要保证WIFI在本次开机以来曾经是打开过的,否则会返回null。所以需要后台尝试先打开WIFI再获取。

 

示例代码:

 

//尝试打开wifi
private static boolean tryOpenMAC(WifiManager manager)
{
boolean softOpenWifi = false;
int state = manager.getWifiState();
if (state != WifiManager.WIFI_STATE_ENABLED && state != WifiManager.WIFI_STATE_ENABLING)
{
manager.setWifiEnabled(true);
softOpenWifi = true;
}
return softOpenWifi;
}

 

//尝试关闭MAC
private static void tryCloseMAC(WifiManager manager)
{
manager.setWifiEnabled(false);
}

 

//尝试获取MAC地址
private static String tryGetMAC(WifiManager manager)
{
WifiInfo wifiInfo = manager.getConnectionInfo();
if (wifiInfo == null || StringUtil.isNull(wifiInfo.getMacAddress()))
{
return null;
}
String mac = wifiInfo.getMacAddress().replaceAll(“:”, “”).trim().toUpperCase();
mac = formatIdentify(mac);
return mac;
}

 

//尝试读取MAC地址
private static String getMacFromDevice(int internal)
{
String mac=null;
WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
mac = tryGetMAC(wifiManager);
if(!StringUtil.isNull(mac))
{
return mac;
}

//获取失败,尝试打开wifi获取
boolean isOkWifi = tryOpenMAC(wifiManager);
for(int index=0;index<internal;index++)
{
//如果第一次没有成功,第二次做100毫秒的延迟。
if(index!=0)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
mac = tryGetMAC(wifiManager);
if(!StringUtil.isNull(mac))
{
break;
}
}

 

//尝试关闭wifi
if(isOkWifi)
{
tryCloseMAC(wifiManager);
}
return mac;
}

 

 

 

==================================================================

 

2. 查询文件路径 /sys/class/net/wlan0/address

 

adb shell cat /sys/class/net/wlan0/address

 

98:6c:f5:10:96:c4

 

但是如果WIFI在本次开机期间从来没有打开过,返回的MAC地址是不同的(非实际的),如下:

 

cat /sys/class/net/wlan0/address
00:90:4c:11:22:33

 

 

 

示例代码:

 

String getMac() {
String macSerial = null;
String str = “”;
try {
Process pp = Runtime.getRuntime().exec(“cat /sys/class/net/wlan0/address”);
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);

 

for (; null != str;) {
str = input.readLine();
if (str != null) {
macSerial = str.trim();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return macSerial;
}
==================================================================

 

3. 查询记录了MAC地址的文件“/proc/net/arp”,但是从测试结果看,返回的数据并不是想要的Wifi Mac地址:

 

比如,手机实际的WIFI Mac地址是98:6c:f5:10:96:c4,但使用adb shell cat proc/net/arp返回的是:

cat proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
192.168.0.3      0x1         0x2         00:23:89:b9:1a:fd     *        wlan0
192.168.0.1      0x1         0x2         08:00:27:7c:65:5a     *        wlan0

[转载].net程序调试一:快速定位异常 - 雨林 - 博客园

mikel阅读(1076)

[转载].net程序调试一:快速定位异常 – 雨林 – 博客园.

作为一个程序员,解BUG是我们工作中常做的工作,甚至可以说解决问题能力是一个人工作能力的重要体现。因为这体现了一个程序员的技术水平、技术深度、经验等等。

那么在我们解决BUG的过程中,定位问题是非常重要的。有句话叫”发现问题是解决问题的一半。

本文讲述就快速定位异常(专指.NET程序异常)的方法。包括在本机定位异常,在客户环境定位.net程序异常,在客户环境定位SilverLight异常。

一:定位本机异常

在我们本机定位异常很容易。假设我们都是使用的的VisualStudio,那么只需要在调试->异常菜单中将Common Langeuage Runtime Exception(CLR异常)勾选。如下图:

在上面的图片中可以发现有5种类型的异常,例如c++异常、win32异常等等。对于.NET程序来说我们只关注CLR异常。

接下来进行调试,当自己的程序代码中有异常的时候,VS就会自动定位到异常的位置。

我们可以看到异常的详细信息,并且可在调用堆栈窗口中看到 程序的堆栈信息。在堆栈信息中我们可以看到在哪个类、哪个函数中出的错,如下图:

 

调试程序有两种方式,一种是用VS直接启动程序,另一种是附加到进程。

 

附加到进程的时候,程序类型不要选错了,我使用的是.net4.0 所以程序类型选择的是 托管(4.0版)代码。

另外附加到进程有个快捷键是 Ctrl+Alt+P。

但是如果异常不是你的代码中抛出的,那么如何定位呢?

可以打开 调试 菜单下面的 选项和设置,将 启用”仅我的代码” 这一项取消勾选。那么别人代码中的异常就可以抛出了。

 

二:在客户环境定位.net程序异常:

我们的程序最后都会运行在客户的环境中,客户环境上不会有VS这样的开发工具,那么怎么办呢?

我们可以使用一个很小巧的命令行调试工具Mdbg.exe,这个工具是安装VS的时候附带安装的,仅能调试.net托管代码。

Mdbg.exe其实有很多功能,不过本文只讲它定位异常的功能,后续文章会讲使用Mdbg.exe单步调试的方法。

Mdbg.exe命令详细介绍可以 输入 h(help) 或者? 名来查看,也可以看下面的链接,

http://msdn.microsoft.com/zh-cn/ms229861(vs.80).aspx#

根据CLR版本的不用,Mdbg.exe也是有多个版本的。

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\Mdbg.exe用于调试

CLR2.0(对应net2.0,3.0,3.5)程序。

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\Mdbg.exe用于调试CLR4.0程序(对用.net4.0)。

另外Mdbg.exe有一个依赖DLL 叫做MdbgCore.dll。我们可以直接将相应版本的Mdbg.exe和MdbgCore.dll拷贝到客户机器上使用。

没有安装VS的朋友可以拷贝我自己封装的一个安装包 http://files.cnblogs.com/yuilin/U8DebugSetup.rar,这里面除了Mdbg.exe还有一些其他组件我们后面的文章会用到。

默认会安装在 C:\Program Files\U8Debug

Mdbg.exe的使用方法很加简,双击打开它,然后输入 a(attach显示附加的进程),回车,这时会列表所有可以附加的进程。

 

PID 表示进程标识,

输入a 11940 附件到 ConsoleApplication2.ex示例程序。

这时程序会中断执行,我们在这个时机可以做一些设置。让程序在遇到异常时自动中断。

输入命令 ca (catch)查看当前调试器遇到哪些事件会中断。

 

可以看到 Exception对应的是Igonre all exception ,也就是忽略所有异常,发生异常时不会中断。

输入命令 ca ex 这样调试器遇到异常时就会中断了。

再次输入ca 命令会看到 Exception对应的值已经变为Stop on all exception了。这时遇到任何异常都会中断了。

 

输入命令 g 让程序继续执行。

当遇到异常时会自动中断到调试器,如下图:

 

入命令 w(where,程序运行到哪里了) 可以查看异常堆栈信息

 

三:在客户环境定位SilverLight异常

如果客户的silverlight应用服务器部署在外网,那么我们可以直接用浏览器访问该silverlight站点,然后用VS附加到浏览器进程来调试。

 

调试方法比调试普通.net程序一样。

但是如果,客户的Silverlight服务器是部署在内网,那么你只能在客户机器上调试了。

并且Mdbg.exe也帮不了你了,它不能调试Silverlight程序。

我们还有另一个著名的调试工具Windbg。体积大概有不到20M,很容易安装到客户机,安装包大家可以到网上自己下载。windbg分为32位和64位两个版本,

调试32位的程序请使用32位windbg,反之则要使用64位的windbg,具体为什么我们不用深究,记住了就可以了。

相比Mdbg.exe的小巧实用,Windbg显然强大的多,但是使用起来也复杂一些。

Windbg其实可以调试很多种类型的程序,例如普通.NET程序,c++等。但是本文只讲解使用windbg定位异常的方法。

首先我们使用IE浏览器打开silverlight应用程序,然后打开windbg附件到IE进程来调试。附加进程的方式可以通过File菜单下的Attach to a process或者使用F6快捷键。

 

附件进程后 程序会中断到调试器,这个时候我们需要做两个设置。

一个是 设置程序发生异常时让其中断到调试器,设置方法是打开Debug菜单下的Event Filter,将CLR异常设置其为enable。

 

另外需要加载调试器扩展,使用过windbg的朋友都知道调试.net程序需要加载一个调试器扩展sos.dll。这个sos.dll也有一个Silverlight版本的。

位置在silverlight的安装目录 C:\Program Files (x86)\Microsoft Silverlight\5.1.10411.0\sos.dll。

我们再command窗口中输入 .load C:\Program Files (x86)\Microsoft Silverlight\5.1.10411.0\sos.dll 来加载它。

之后输入命令 g 来回复程序的执行。当发生异常时就会中断到调试器中。

发生异常是我们可以使用!pe(print exception) 来查看异常信息。如下图:

 

如果想查看堆栈信息的话可以输入命令 !clrstack

通过上述方法基本可以定位所有的.NET异常。至此,本文结束。

[转载]安卓模拟器bluestacks mac地址修改教程 实测可用_口袋巴士

mikel阅读(1782)

[转载]安卓模拟器bluestacks mac地址修改教程 实测可用_口袋巴士.  很多朋友都很喜欢使用bluestacks来玩安卓游戏,但是我们都知道,很多安卓网游都是需要使用到MAC地址的,所以如何找到并修改 bluestacks mac地址是很重要的,本篇教程就是教大家如何找到并修改或者更正bluestacks mac地址,有兴趣的朋友可以来学习下。
首先放出几张截图,是修改过MAC地址后的截图:

 

准备工具

 

文件名称

文件大小

下载地址
MAC地址修改器

6KB

点击下载

 

bluestacks mac地址修改教程:

1、然后正式开始教程,注意,首先确保你的安卓模拟器bluestacks已经完全关闭,如果你是老版本的模拟器,还需要在任务管理器中将模拟器进程杀掉,如果是最新版本的,直接点击“离开”就可以了;

注意:如果不完全关闭BS模拟器,会造成MAC地址修改失败。
2、然后下载并解压bluestacks mac地址修改器;

3、bluestacks mac地址修改第3步,然后找到MAC地址修改器.exe这个程序,双击运行,会出现下图这个界面;

 

  运行后会出现下图这个界面:

 

4、然后我们先点击“生成GUID”,再点击生成“IMEI”;

5、最后点击“写入注册表”即可。

这样就成功修改了bluestacks mac地址,接下来我们只需要重启模拟器就可以了。
注意:以后如果你想要修改IMEI码,都需要关闭并重启MAC地址修改器.exe这个工具才可以。此外MAC地址修改完毕后,使用RE管理器或bluestacks mac地址修改者是ES管理器都可以查看模拟器的MAC地址变动。
本篇bluestacks mac地址修改教程到这里就结束了,希望可以帮助到大家哦。

[转载]Android中使用RadioButton代替ImageButton - wavky - 博客园

mikel阅读(1178)

[转载]Android中使用RadioButton代替ImageButton – wavky – 博客园.

画外音————好久没上来发文章了,这几个月一直忙着一些跟编程不沾边的事,拖了好久,现在还在持续中,顺利的话7月份应该能解放了。。今天偶尔上来写一段番外篇性质的心得发现。


 

之前搞的Android项目,作为底部导航工具栏,一直用的是普通的ImageButton,搭配几张漂亮的图片,写写监听器就完事,效果看下面的 图,虽然简单,但是有一个不太好的缺点,那就是导航到新的页面的时候,都要手动处理这个按钮的点击状态(让它高亮底图)和其它按钮的点击状态(让之前的退 出高亮),这个处理过程既繁琐又容易遗漏出错等等等等..

 

受同事启发,使用RadioGroup和RadioButton就能自动化的解决上面的问题,因为本质上一个RadioGroup内只允许一个 RadioButton处于选择状态之下(高亮),点击了同一组的其它RadioButton,之前的RadioButton就会自动被处理掉,而且当前 RadioButton选择状态会自动保留,根本不需要再像之前的ImageButton那样一个个写处理代码,既美观又环保。

想法很不错,动手开干,但是又发现了一个新问题:RadioButton的样式在不同的系统版本表现不一样!下面拿这个超萌的猪头来说明情况。

素材图片:

RadioButton布局脚本:


其中 Android:button=”@null” 这句很重要,用来消除掉RadioButton标配的圆圈单选按钮!

而 Android:drawablePadding=”-20dp” 是用来去掉标配分给RadioButton文本的空位,当图片素材画在了drawableTop上面时,对应的文本会出现在下方,如果不需要填入文本,就用这行代码去掉空位;如果选择画在drawableLeft的话,就不需要这一行。

 

具体来说分两种情况,一种是API17(4.2.2)中的表现:

另外一种是API14(4.0)以及它之下的各版本(如API8)中的表现:

   

上面API14和API8的效果是一样的,跟API17对比很明显,就是图片的左边多了一个空位!!这个位置无论怎么调padding、margin之类的参数都无法完全消除掉,很恶心。

至于API17-API14之间到底是哪个系统版本成了分水岭,这个就不得而知了,笔主这边编译环境没有安装更多的版本了,也懒得去研究。

 

上面这个问题找了好久都没找到原因,甚至于笔主都漫无目的的百度搜索有木有针对不同系统版本使用不同布局文件的方法了…

理所当然的一个但是,笔主本着不依不饶的顽强精神再次检查RadioButton布局属性参数,幸运女神终于降临了,笔主发现一个隐藏已久的陷阱:background!! 这个属性在API17的时候是空的,但是  在API14以下竟然默认配置成了 @android:drawable/btn_radio_label_background !!!既然发现了问题,笔主就二话不说直接填上伟大的 @null ,F5刷新一下屏幕..果不其然,一切又回归自然了!

(左右那俩二货没有弄background,所以还是那副鸟样)

 

处理后的RadioButton布局代码是:


RadioGroup开始的整体代码是:(上面的RadioButton参数被我放到了style文件里面)


&nbsp;

&nbsp;

开头所说的选择的时候高亮状态,需要设置相应的selector处理图片素材,这里就不详细说明了。

至此,RadioButton已经能够透明的代替ImageButton了,向下兼容至API8,并带入自动标记高亮单项选择功能,做导航的话应该比单纯的ImageButton更具优势吧,呵呵。

 

ps. 因为需要动态增减RadioButton等原因,在代码中设置新RadioButton对象的属性可参考以下博文:

Android中代码设置RadioButton的高端技巧

[转载]自己动手搞定支付宝手机网站支付接口 FOR ECShop - x3d - 博客园

mikel阅读(811)

[转载]自己动手搞定支付宝手机网站支付接口 FOR ECShop – x3d – 博客园.

支付宝WAP网站版本的支付接口网上整合的比较少,看到很多网站在卖,顿觉无语。

主要是得自己查看支付宝官方提供的SDK中的开发文档。

支付宝sdk下载地址:http://club.alipay.com/read-htm-tid-9976972.html

 

1. 要使用支付宝手机网站支付接口,除了要配置基本的帐号外,还必须配置openssl密钥文件。关于key的生成,一定要看文档,在此不详述。文档上演示的在线上传key的界面地址为:https://mobiless.alipay.com/home/index.htm ,key一定要存在,而且地址要正确,不然支付宝那边不能返回有效的界面

2.以独立的支付接口形式提供,便于用户根据自己的需求再做定制;

3. 附件提供的代码是简单的集成,仅起一个演示作用,没有考虑代码的复用性之类

 

ecshop支付宝手机网站支付接口下载地址: http://files.cnblogs.com/x3d/ecshop_payment_alipay_wap.zip

本文来源:http://www.cnblogs.com/x3d/,转载请注明。

[转载]浅析正则表达式—(原理篇) - Mr.小丁 - 博客园

mikel阅读(834)

[转载]浅析正则表达式—(原理篇) – Mr.小丁 – 博客园.

前言:

  其实这篇文章很久之前就应该发出来,由于种种原因没有 发出来,如果这篇文章中有错误,还请大家指出,小弟并改正之,没有学不会的东西,只有不想学的东西,只要功夫深,铁杵磨成针,我的至理名言:吾生也有涯而 知也无涯,以有涯随无涯,殆矣。我们只要坚持将其看完,相信大家的正则表达式会有一个提升空间!本文属于.NET正则表达式里面的内容,由于不同语言正则 表达式有所不同。

首先先讲解下正则表达式的基础知识:

  1.字符串的组成

  对于字符串”123“而言,包括三个字符四个位置。如下图所示:

  2.占有字符和零宽度

  正则表达式匹配过程中,如果子表达式匹配到东西,而并 非是一个位置,并最终保存到匹配的结果当中。这样的就称为占有字符,而只匹配一个位置,或者是匹配的内容并不保存到匹配结果中,这种就称作零宽度,后续会 讲到的零宽度断言等。占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表 达式匹配。

  3.控制权和传动

  正则表达式由左到右依次进行匹配,通常情况下是由一个 表达式取得控制权,从字符串的的某个位置进行匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的(例如:(表达式一)(表达 式二)意思就是表达式一匹配完成后才能匹配表达式二,而匹配表达式二的位置是从表达式一的位置匹配结束后的位置开始)。如果表达式一是零宽度,那表达式一 匹配完成后,表达式二匹配的位置还是原来表达式以匹配的位置。也就是说它匹配开始和结束的位置是同一个。

  

  举一个简单的例子进行说明:正则表达式:123

  源数据:123

  讲解:首先正则表达式是从最左侧开始进行匹配,也就是 位置0处进行匹配,首先得到控制权的是正则表达式中的“1”,而不是源数据中的“1”,匹配源数据中的“1”,匹配成功,将源数据的“1”进行保存到匹配 的结果当中,这就表明它占有了一个字符,接下来就将控制权传给正则表达式中的“2”,匹配的位置变成了位置1,匹配源数据中的“2”,匹配成功,将控制权 又传动给了正则表达式的“3”,这时候匹配的位置变成了位置2,这时候就会将源数据中的“3”进行匹配。又有正则表达式“3”进行传动控制权,发现已经到 了正则表达式的末尾,正则表达式结束。

一、元字符

限定符 描述 模式
.

匹配出换行符以外的任意字符

\d*\.\d

\w

匹配字母数字或下划线或者汉字或者下划线

“be+”
\s

匹配任意空白符

  

“rai?n”
\d

匹配数字

“,\d{3}”
\b

匹配单词开始或结束,它只是匹配一个位置

“\d{2,}”
^

匹配字符串开始

“\d{3,5}”
$

匹配字符串结束

“\d{3,5}”

 

二、转义字符

如果你想要得到元字符本身的话需要使用“\”来取消这些元字符的特殊意义

 

三、字符类

  首先字符类使用“[]”包起来的,例如以下这个例子:(大小写要区分)

  ①[aeiou]则表示匹配任意一个英文元音字母(这个仅仅是匹配一个,也就是说你如果匹配了a这个整个正则表达式就已经结束了,这里面的逻辑表示的是“或”的意思),再看这个例子[.!?]表示匹配.或者?或者!

  ②[a-zA-Z0-9]这个正则表达式表示的是匹配a到z的任意一个小写字母,或者是A到Z的任意一个字母,或者是数字0到9任意一个.

四.重复(MSDN上称作是限定符)

代码/语法

说明

*

重复0次或多次

+

重复一次或多次

?

重复零次或1次

{n}

重复n次

{n,}

重复至少n次

{n,m}

重复至少n次,但不多于m次

 

五.分支条件

  其实正则表达式中的分支条件,就指的是有几种规则:用“|”把不同的规则分开

  来看下例子:

  ①0\d{2}-\d{8}|0\d{3}-\d{7}:匹配两种以连字号分隔的电话号码;一种是三位区号8位本地号(例如:010-12345678),另外一种规则则是4位区号7位本地号(例   如:0315-8834524)

  ②\d{5}-\d{4}|\d{5}:需要注意的是 使用分支条件是一定要注意分支条件的顺序,如果改成\d{5}|\d{5}-\d{4}这个样子的话,那么只会匹配五位数字而不会匹配后面的四位数字(例 如:我们利用第二个匹配12345-1234,它只会匹配12345,原因是:正则表达式是从左到右依次匹配,如果满足了某个分支的话它就不会再管其他分支了)

 

六.分组

  你可以使用小括号()来指定字表达式

  ①(\d{1,3}){3}\d{3}:这个正则表达式的意思就是把我们分组的小括号里面的东西重复三次,也就是说我们至少匹配3个最多匹配9个数字,后面再加上三个数字

 

  我们可以看图,最后一个是1234567891 123也就是说前面是十个数字按照我们的常理来分析的话就应该匹配应该最多的是9个所以匹配之后的数到2就匹配成功了。

  OK我们讲到分组不知道你们对上面这幅图有没有什么想法?对,没错就是为啥还有0,1之分呢?想知道答案跟我继续看下去,保证你有意外收获哦!

  也许大家会问为什么这里的写的1里面匹配的是这些数字,我们稍后我们会为你解析这是为什么会是这些数字!

七.反义字符

代码/语法

说明

\W

匹配任意一个不是字母或数字下划线或汉字的字符

\S

匹配任意一个不是空白符的字符

\D

匹配不是数字的字符

\B

匹配不是单词开头或者结尾的位置

[^X]

匹配除了X以外的任意字符

[^aeiou]

匹配除了aeiou这几个字母以外的任意字符

 

八.反向引用

  使用小括号指定一个子表达式后,匹配这个子表达式的文 本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标 志,第一个出现的分组的组号为1,第二个为2,以此类推。但是其实分组号不是这么简单:

  •分组0对应整个正则表达式

  •实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号

  •你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.

  通过上面三条讲述我们可以清楚地知道分组的方式是怎样 的,其实意思就是首先我们先对没有为组进行命名的组进行分配组号(从左到右依次次分配),然后再对分配组号的组进行分配组号(使用(?<组 名>)方式显示分配组名称),如果你想剥夺某一个组的组号可以采用(?:exp)这种方式进行剥夺,也就是不给他分配组号,可以理解为跳过此组。看 一下例子:

  正则表达式:(?<work>3)(1)(2)(?<SmallDing>565)

  匹配文本:312565

  匹配结果表明首先0号组的是匹配的整个表达式,匹配1号组名的则是1,匹配2号组的是2,匹配3号组的就是命名为work组名的3,匹配4号组的则是匹配命名为SmallDing组名的565,显然可以看到分配组号就是按照以上的规则来分配。

说到了反向引用我们来看一下反向引用是什么概念,我们前面已经详细讲解了组号的分配,那么反向引用则用于重复搜索前面某个分组匹配的文本,例如\1代表分组1匹配的文本

请看下面的例子:

  正则表达式:(1)(2)(3)\2则表示匹配123且在此匹配组号为2的内容也就是再次匹配2

  匹配文本:1232

  匹配结果如下图所示:

  而至于想知道怎样取消分组号那就跟着我的脚步走,来看看下面的内容吧!

  正则表达式:(?<work>333) (?<smallDing>222)(?:\d{3})该正则表达式代表的是显示为匹配333的组分配组名为work,显示为匹配222结果 的组分配组名为222,但是如果匹配3位数字这个组已经取消了组号,所以该组号是没有的,也就是整个正则表达式是第一个组号为0,首先将所有未命名的组进 行分配组号,而只有一个(?:\d{3})这个没有分配组名,但是它却将组号进行取消了,所以组号不会给它分配。

  源文本为:333222123

  匹配结果为:如下图所示:

那现在我们就来讲一下零宽断言和负零宽断言

常见的几种分组方法

分类

代表/语法

说明

 

 

捕获

 

 

(exp)

匹配exp,并捕获文本到自动命名的组里

(?<name>exp)

匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp)

(?:exp)

匹配exp,不捕获匹配文本,也不给分组分配组号

 

 

 断言

 

 

 

(?=exp)

匹配exp前面位置,但是不匹配exp

(?<exp)

匹配exp后面位置,但是不匹配exp

(?!exp)

匹配后面的不是exp的位置,但是不匹配exp

(?<!exp)

匹配前面不是exp的位置,但是不匹配exp

注释

(?#comment)

注释

  零宽度断言

  1.(?=exp):也叫零宽度正预测先行断言,它匹配自身出现的位置后面能匹配表达式exp

  例如:\b\w+(?=ing\b)则这个正则表达式 就是匹配一ing结尾的单词,但是不包含ing,这个零宽度正预测先行断言可以这样理解,我们就以上面的正则表达式作为例来进行讲解,首先我们肯定是匹配 源文本为doing它会先匹配d的时候它会瞻仰一下后面跟的是不是ing,如果不是就会继续往下走,匹配到第二个字符o它会预测(或瞻仰)下后面是不是 ing如果是整个表达式就结束了,并且不匹配ing。而这个可以总结一句话就是匹配exp前面的东西

  2.(?<=exp):也叫零宽度正回顾断言, 它匹配自身出现位置的前面匹配表达式exp,这句话听着很绕口,其实零宽度正回顾断言中解释说是自身出现位置这个自身出现位置是表示它匹配的文本,就比如 说(?<=Ding)\d{3}这个正则表达式,这里的自身出现的位置仅仅是从开始匹配文本的时候也就是\d{3}也就是主动权在这个\d{3}的 时候才是自身匹配的位置。举例说明源文本,比如匹配Din123,按照我们的常理理解的是数字123是自身匹配的位置,但是前面不是Ding所以匹配不成 功,我们可以讲这个表达式理解为就是以exp为开始的正则表达式但是不包含exp,意思就是匹配exp后面的东西。

  负向零宽断言:(可以和上面的进行对比来学哦!这个表达式的是否定的)

  1.(?!exp):也叫零宽度负预测先行断言,断言此位置的后面跟的不能匹配表达式exp,

  例如:\d{3}(?!123):正则表达式的含义表达了前面匹配的是三个数字,匹配的位置就是当前匹配的这三个数字后面跟的不能是123。

  2.(?<!exp):零宽度负回顾断言,断言此位置前面跟的不是exp的位置。

  九.平衡组

  接下来我来讲一下平衡租的原理,在上面我们做下了铺 垫,也就是说我们在第六节的时候提出来了一系列问题,是不是感觉一头雾水,没关系的,到了这一节终于守得云开见月明了,听过本章节的学习我相信你们会对上 面的问题进行一个详细合理的回答!OK,Come On Baby!懂你们迫不及待心情,一定会说你咋这多废话呢,好,闲话少说,继续….

说到平衡组有些人就会想到分组,没错他们之间是有联系的,也就是我们前面所讲的分配组号的问题,那下面呢我们先引出语法,详细见下表

语法

说明

(?’group’)

把捕获的内容命名为group,并压入堆栈

(?’-group’)

从堆栈上弹出最后压入堆栈名为group的捕获内容,如果堆栈为空则本组匹配失败

(?(group)yes|no)

如果堆栈上存在名为group的捕获内容的话,继续匹配yes部分的表达式,否则匹配no的表达式

(?!)

零宽度负先行断言,由于没有后缀表达式,试图匹配总是失败

  也许大家看到这些语法都不知道是什么概念,也不知道这 个平衡组到底用在什么地方合适,接下来我们我们就来说一个场景分析它用在什么位置比较合适,有时我们需要匹配像 ( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内 容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如 ( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢? 为了避免(和\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把 xx <aa <bbb> <bbb> aa> yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?

  接下来我们对这些语法进行分析,怎么样一个平衡法,大家都见过第一个语法,语法的内容讲解的就是为一个组分配组名,这里我们为什么还强调一下分配组名的问题么?前面不是提到过这些问题了么!那现在让我们解析一下平衡法以及用这些语法去构建一个平衡。

  我们先以一个例子开始,正则表达式: (?’Group’123)(?’Group’456)看这个正则表达式,你会发现一些问题,恩?怎么给两个组分配了一个组名,这样返回的Group组名 获取的到底是个什么东东呢?大家来猜一下(匹配文本:123456)会是个什么结果?

先看一下测试结果:

我们可以看到0组当人不让的是整个表达式的,而Group组里面获取的是456,而不是123,这是为什么呢?那么我们就来分析一下他的原理,一张图搞懂原理

  OK,我们来讲一下组其实内部是一个堆栈,也就是我们 分别往组名为Group的堆栈中放入了两个内容,第一个压入栈的是123,而第二压入栈的是456,Group组获取的文本是堆栈的top,也就是栈顶的 数据,所以Group获取的数据是456,而不是123,那么有些人说了我不想要456,我就想要123怎么实现?这样也好办啊!我们就弹出栈顶数据不就 行了么!

  看下面的实例:(?’Group’123)(?’Group’456)(?’-Group’)这里的表达式(?’-Group’)就是压出堆栈栈顶的数据也就是如下图所示的:

 

  那么现在栈顶的数据就是123了,那么我们就来看一下匹配的结果是不是我们想的这样:

  

  那么我们就可以想到分组名的是这样没有分组名的组也是 这样的匹配原理那么我们回到第六章就可以将答案找出来,为什么这个组里的数据会是这个了!剩下还有(?(group)yes|no)深入讲解下这个表达式 是什么意思,我们前面已经讲到了分组是一个堆栈,可以压入和弹出,但是再弹出的时候我们不知道它有没有弹完用什么办法来可以检测它是不是已经到了栈底了 呢?那么用这个正则表达式就可以检测到!它说的意思就是如果我们已经将数据全部都弹出去了就会执行一个表达式在No的位置,“|”表示分割两种不同情况, 如果还存咱数据就说明还没有到栈底,就会执行yes的表达式。那么我们就开始举例说明:正则表达式:(?’group’123) (?’group’456)(?’-group’)(?(group)1|2):这个表达式含义就是如果堆栈中还有数据就匹配1,否则就匹配2,看下面测 试结果表明堆栈中还有数据。

 

十、贪婪与非贪婪

  首先先说一下关于贪婪匹配和非贪婪匹配的一些基本概念,贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。

  下面是一些限定符(限定符指定在输入字符串中必须存在上一个元素(可以是字符、组或字符类)的多少个实例才能出现匹配项)

  贪婪匹配的限定符如下表所示:

限定符 描述 模式 匹配
* 匹配上一个元素零次或多次 \d*\.\d “.0″,”19.9″和”219.9”
+ 匹配上一个元素一次或多次 “be+” “been”和”bee”,”bent”和”be”
匹配前面的元素零次或一次   “rai?n” “ran”和”rain”
{n} 匹配上一个元素恰好n次 “,\d{3}” “1.043.6”中的.043
{n,} 匹配上一个元素至少n次 “\d{2,}” “166”,”29″和”1930″
{n,m} 匹配上一个元素至少n次,但不多于m次 “\d{3,5}” “166”,”16546″,”132654″中的13265

  非贪婪是在贪婪限定符后面多加一个“?”,如下表所示:

  

限定符 描述 模式 匹配
*? 匹配上一个元素零次或多次,但次数尽可能少 \d*?\.\d “.0″,”19.9″和”219.9”
+? 匹配上一个元素一次或多次,但次数尽可能少 “be+?” “been中的”be”,bent”中的”be”
?? 匹配上一个元素零次或一次,但次数尽可能少 “rai??n” “ran”和”rain”
{n}? 匹配前导元素恰好 n 次 “,\d{3}?” “1.043.6”中的.043
{n,}? 匹配上一个元素至少 n 次,但次数尽可能少 “\d{2,}?” “166”,”29″和”1930″
{n,m}? 匹配上一个元素的次数介于 n 和 m 之间,但次数尽可能少 “\d{3,5}?” “166”,”16546″,”132654″中的”132″,”654″

 

十一、贪婪匹配和非贪婪匹配原理

  这是最后一章节,也是最难理解的一章节了,希望大家跟 进脚步学习下!其实这节贪婪匹配与懒惰匹配应该放在重复后面讲,因为这个和重复有关系,那么下面详细介绍什么是贪婪匹配什么是非贪婪匹配,贪婪与非贪婪模 式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能 少的匹配。非贪婪模式只被部分NFA引擎所支持。

  从原理角度分析一下贪婪匹配与懒惰匹配,接下来我们将以一个例子分析

  匹配两个正则表达式,正则表达式一为:.*

  正则表达式二是:.*?

  源文本是:“Regex”

  (1).贪婪

  

  注:为了能够看清晰匹配过程,上面的空隙留得较大,实际源字符串为“”Regex””,下同。

  来看一下匹配过程。首先将控制权交给“””,由它来匹 配第一个字符”匹配成功,将控制权转交给“.*”,这时候控制权掌握在了“.*”的手上,由于“*”是优先词量,在可匹配与不可匹配的情况下,优先尝试匹 配,他就会尝试匹配第一字符R,匹配成功就会继续往下匹配,匹配第二字符e,匹配成功,继续向右匹配,直到匹配到结尾的“””,匹配成功,再向后匹配时发 现已经到结尾了,“.*”结束匹配将控制权转交给”””,”””发现已经到了源字符串的结尾,看有没有可供回溯的状态,将控制权给了“.*”,“.*”还 回一个字符“x”,然后将控制权转交给“””,来匹配后面的字符“””,匹配成功正则表达式结束。这句表达式只进行了一次回溯。

  (2).懒惰

  源字符串:”Regex” 

  正则表达式:”.*?” 

  看一下非贪婪模式的匹配过程。首先由第一个“””取得 控制权,匹配位置0位的“””,匹配成功,控制权交给“.*?”。“.*?”取得控制权后,由于“*?”是忽略优先量词,在可匹配可不匹配的情况下,优先 尝试不匹配,由于“*”等价于“{0,}”,所以在忽略优先的情况下,可以不匹配任何内容。从位置1处尝试忽略匹配,也就是不匹配任何内容,将控制权交给 正则表达式最后的“””。 

  “””取得控制权后,从位置1处尝试匹配,由“””匹配位置1处的“R”,匹配失败,向前查找可供回溯的状态,控制权交给“.*?”,由“.*?”吃进一个字符,匹配位置1处的“R”,再把控制权交给正则表达式最后的“””。

  “””取得控制权后,从位置2处尝试匹配,由“””匹配位置1处的“e”,匹配失败,向前查找可供回溯的状态,重复以上过程,直到由“.*?”匹配到“x”为止,再把控制权交给正则表达式最后的“””。 

  “””取得控制权后,从位置6处尝试匹配,由“””匹配字符串最后的“””,匹配成功。 

  此时整个正则表达式匹配成功,其中“.*?”匹配的内容为“Regex”,匹配过程中进行了五次回溯。 

 

  写的很认真但是难免会有错误,希望大家多多包涵,多多指出,时刻保持学习的身段,正所谓三人行必有我师焉。人外有人天外有天,只有保持不断学习的精神,才能达到我们的目标。我会将其更新并且改正。

  这篇文章为了方便大家传阅将其写成word文档,可以进行下载,下载地址如下:

  百度网盘:http://pan.baidu.com/s/1kTKB3Zx 提取密码:l6q4

  其中有我在公司的技术分享视频,由于是第一次录制可能有些细节没有讲得很清楚。也在上面百度网盘中。

  参考文章:

  图片是从下面文章中找到的:

    http://www.jb51.net/article/31491.htm

  http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html#mission

  测试工具也在里面:

  http://deerchao.net/tutorials/regex/common.htm

  谢谢各位的提的意见,从你们的意见中将这篇文章尽自己最大努力完善,这篇文章写得不完美,需要大家的努力。

   接下篇对令宽度进行详细讲解:

   浅析正则表达式——柳暗花明又一村篇