iOS 3D卡片式轮播

效果:

%title插图%num

参考UITableView的UITableViewDataSource和UITableViewDelegate两个方法实现;支持五险轮播,可以加载本地图片,也可以加载网络图片,可以根据自己的需求自定义
Demo地址

UITableViewDelegate

1 /**
2  *  当前显示cell的Size(中间页显示大小)
3  *
4  *  @param flowView <#flowView description#>
5  *
6  *  @return <#return value description#>
7  */
8 – (CGSize)sizeForPageInFlowView:(HQFlowView *)flowView;
9
10 /**
11  *  滚动到了某一列
12  *
13  *  @param pageNumber <#pageNumber description#>
14  *  @param flowView   <#flowView description#>
15  */
16 – (void)didScrollToPage:(NSInteger)pageNumber inFlowView:(HQFlowView *)flowView;
17
18 /**
19  *  点击了第几个cell
20  *
21  *  @param subView 点击的控件
22  *  @param subIndex    点击控件的index
23  *
24  *  @return <#return value description#>
25  */
26 – (void)didSelectCell:(HQIndexBannerSubview *)subView withSubViewIndex:(NSInteger)subIndex;

 

UITableViewDataSource

1 /**
2  *  返回显示View的个数
3  *
4  *  @param flowView <#flowView description#>
5  *
6  *  @return <#return value description#>
7  */
8 – (NSInteger)numberOfPagesInFlowView:(HQFlowView *)flowView;
9
10 /**
11  *  给某一列设置属性
12  *
13  *  @param flowView <#flowView description#>
14  *  @param index    <#index description#>
15  *
16  *  @return <#return value description#>
17  */
18 – (HQIndexBannerSubview *)flowView:(HQFlowView *)flowView cellForPageAtIndex:(NSInteger)index;

pytorch 自定义初始化权重的方法

pytorch 自定义初始化权重的方法

首选注意:torch.ensor 与 torch.Tensor的区别
常用操作 torch.tensor是一个包含多个同类数据类型数据的多维矩阵。
常用参数
dtype: tessor的数据类型,总共有八种数据类型。其中默认的类型是torch.FloatTensor,而且这种类型的别名也可以写作torch.Tensor。

核心思想就是构造和该层权重同一尺寸的矩阵去对该层权重赋值。但是,值得注意的是,pytorch中各层权重的数据类型是nn.Parameter,而不是Tensor或者Variable**。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

*一个卷积层,我们可以看到它的权值是随机初始化的
w=torch.nn.Conv2d(2,2,3,padding=1)
print(w.weight)

*种方法
print(“1.使用另一个Conv层的权值”)
q=torch.nn.Conv2d(2,2,3,padding=1) # 假设q代表一个训练好的卷积层
print(q.weight) # 可以看到q的权重和w是不同的
w.weight=q.weight # 把一个Conv层的权重赋值给另一个Conv层
print(w.weight)

第二种方法
print(“2.使用来自Tensor的权值”)
ones=torch.Tensor(np.ones([2,2,3,3])) # 先创建一个自定义权值的Tensor,这里为了方便将所有权值设为1
w.weight=torch.nn.Parameter(ones) # 把Tensor的值作为权值赋值给Conv层,这里需要先转为torch.nn.Parameter类型,否则将报错
print(w.weight)

完整实现线性权值变化
#===================================================
x = torch.randn(128,20) # N = 128组,特征20
print(x.size())
m = torch.nn.Linear(20,30) # 输入特征数、输出特征30
# m.weight = torch.rand(30,20)
new_Wight = torch.Tensor(np.ones([30,20])) # torch.Tensor = torch.FloatTensor 默认float类型
m.weight = torch.nn.Parameter(new_Wight) # 自定义权值初始化

print(m.weight.size()) # 权值 30*20
print(m.bias.size()) # 偏置 30

out = m(x)
print(out.size())

print(m.weight)
print(m.bias)
# print(list(m.parameters())) # 查看参数

参考:https://www.jb51.net/article/167881.htm

附:Variable和Parameter的区别
Parameter是torch.autograd.Variable的一个子类,常被用于Module的参数。例如权重和偏置。

Parameters和Modules一起使用的时候会有一些特殊的属性。parameters赋值给Module的属性的时候,它会被自动加到Module的参数列表中,即会出现在Parameter()迭代器中。将Varaible赋给Module的时候没有这样的属性。这可以在nn.Module的实现中详细看一下。这样做是为了保存模型的时候只保存权重偏置参数,不保存节点值。所以复写Variable加以区分。

另外一个不同是parameter不能设置volatile,而且require_grad默认设置为true。Varaible默认设置为False.

参数:

parameter.data 得到tensor数据

parameter.requires_grad 默认为True, BP过程中会求导

Parameter一般是在Modules中作为权重和偏置,自动加入参数列表,可以进行保存恢复。和Variable具有相同的运算。

我们可以这样简单区分,在计算图中,数据(包括输入数据和计算过程中产生的feature map等)时variable类型,该类型不会被保存到模型中。 网络的权重是parameter类型,在计算过程中会被更新,将会被保存到模型中。

 

Python中 掌握Data Frame的常用操作

Python中 掌握Data Frame的常用操作

掌握Data Frame的常用操作
一. 查看DataFrame的常用属性
DataFrame基础属性有:values(元素)、index(索引)、columns(列名) 、dtypes(类型)、size(元素个数)、ndim(维度数)和 shape(形状大小尺寸),还有使用T属性 进行转置

import pandas as pd
detail=pd.read_excel(‘E:\data\meal_order_detail.xlsx’) #读取数据,使用read_excel 函数调用
# print(detail)
print(“索引”,detail.index)
print(“所以 值 :”,detail.values)
print(“所以列名:”,detail.columns)
print(“数据类型:”,detail.dtypes)
print(“元素个数:”,detail.size)
print(“维度:”,detail.ndim)
print(“形状大小 尺寸:”,detail.shape)
#使用T属性 进行转置
print(“转置前的形状:”,detail.shape)数据
print(“转置后的形状:”,detail.T.shape)

二. 查改增删DataFrame数据

查看访问DataFramezhon’的数据
(1.1)DataFrame数据的基本查看方式
#使用字典访问方式
order_id=detail[‘order_id’]
print(“订单详情表的order_id的形状:”,order_id.shape)
#使用访问属性的方式
dishes_name=detail.dishes_name
print(“订单详情表中的dishes_name的形状:”,dishes_name.shape)
#DataFrame 单列多行的数据获取
dishes_name5=detail[‘dishes_name’][:5]
print(dishes_name5)
#多列多行数据
orderDish=detail[[‘order_id’,’dishes_name’]][:5]
print(orderDish)
#访问多行数据
order5=detail[:][1:6]
print(“订单详情表中的1~6行元素的数据:\n”,order5)

#使用DataFrame的head和tail方法获取多行数据
print(‘订单详情表中前5行数据:\n’,detail.head())#head()里面没有参数的话,默认为5行
print(‘订单详情表中后5行数据:\n’,detail.tail()) #tail()里面没有参数的话,默认为5行

(1.2) .DataFrame的loc和iloc访问方式;

dishes_name1=detail.loc[:,’dishes_name’] #DataFrame.loc[行索引名称或条件,列索引名称]
print(“使用loc提取dishes_name列的size:”,dishes_name1.size)
dishes_name2=detail.iloc[:,3] #DataFrame.iloc[行索引位置,列索引位置]
print(“使用iloc提取第3列的size:”,dishes_name2.size)

#使用loc、iloc 实现多列切片
orderDish1=detail.loc[:,[‘order_id’,’dishes_name’]]
print(orderDish1.size)
orderDish2=detail.iloc[:,[1,3]]
print(orderDish2.size)
#使用loc、iloc 实现花式切片
print(“列名为order_id和dishes_name 的行名为3的数据:\n”,detail.loc[3,[‘order_id’,’dishes_name’]])
print(‘列名为order_id和dishes_name 行名为2、3、4、5、6的数据为:\n’,detail.loc[2:6,[‘order_id’,’dishes_name’]])
print(‘列名1和3,行位置为3的数据为:\n’,detail.iloc[3,[1,3]]) #这里为什么不可以loc函数,
#因为loc函数传入的是列索引的名称(或行的名称或条件),而iloc传入的是位置
print(‘列位置为1和3,行位置为2,3,4,5,6的数据和:\n’,detail.iloc[2:7,[1,3]])#这里是位置索引,7是取不到的
#使用loc和iloc函数实现条件切片
print(‘detail中order_id为458的dishes_name为:\n’,detail.loc[detail[‘order_id’]==458,[‘order_id’,’dishes_name’]]) #使用了loc
print(“detail中order_id为458 的第1、5列的数据为:\n”,detail.iloc[(detail[‘order_id’]==458).values,[1,5]])#values 获取元素 #使用iloc函数

(1.3).ix切片方法

#使用loc、iloc、ix 实现切片 比较(DataFrame.ix[行的索引或位置或条件,列索引名称和位置])
print(‘列名为dishes_name行名为2,3,4,5,6的数据为:\n’,detail.loc[2:6,[‘dishes_name’]])
print(‘列位置为5行名为2~6的数据为:\n’,detail.iloc[2:6,5])
print(‘列位置为5行名为2~6的数据为:\n’,detail.ix[2:6,5])

2.更改DataFame中的数据

#将order_id为458 的改成 45800
detail.loc[detail[‘order_id’]==458,’order_id’] = 45800 #45800 这里 没有单引号的
print(‘更改后detail中的order_id为 458 的:\n’,detail.loc[detail[‘order_id’]==458,’order_id’])
print(‘更改后detail中的order_id为 45800 的:\n’,detail.loc[detail[‘order_id’]==45800,’order_id’])
detail.loc[detail[‘order_id’]==45800,’order_id’] = 458

3.为DataFrame增添数据

#新增一列非定值
detail[‘payment’]=detail[‘counts’]*detail[‘amounts’]
print(‘detail新增列payment的前5行数据为:\n’,detail[‘payment’].head())
#新增一列定值
detail[‘pay_way’]=’现金支付’
print(‘detail新增列的前5行的数据为:\n’,detail[‘pay_way’].head())
“4.删除某行或某列的数据(drop)
#删除某列
print(‘删除pay_way前 detail中的列索引为:\n’,detail.columns)
detail.drop(labels=’pay_way’,axis=1,inplace=True)
print(‘删除pay_way后 detail中的列索引为:\n’,detail.columns)
#删除某几行
print(‘删除1~10行 前 detail的长度:’,len(detail))
detail.drop(labels=range(1,11),axis=0,inplace=True)
print(‘删除1~10行 后 detail的长度:’,len(detail))

三. 描述分析DataFrame数据
1.数值特征的描述性统计
describe()函数描述性统计
2.类别类特征的描述性统计
object类型,categroy类型

公有云市场, SaaS难逃厄运

云计算寡头的呈现有利有弊,到底是弊大于利仍是利大于弊呢?

亚马逊AWS开端展现其在公有云中的商场分配能力时宣称:“我们不与友商竞赛”,“我们正在瞄准一个特定的范畴,这就是AWS的优势”。

笔者对此不以为然,AWS正在与每个云计算企业竞赛,因为它业务范围太广,就好像它现在没有为商场供给特定的SaaS效劳,却不代表AWS今后不会供给这类效劳一样。

随之而来的是微软Azure,越来越剧烈的竞赛使得商场份额更加死板,池塘中的小鱼更难坚持满足的生机。

证据清楚明了,HPE、Rackspace等等实际上现已退出了公有云商场,他们现在与其他公司协作供给办理效劳或混合产品。

商场为每家企业都留有空间,挑选必定仍是重要的,可是寡头独占开端构成。

依据Forrester的研讨,AWS和微软Azure本年将占公有云商场的四分之三,而桌面应用中,微软、谷歌和Adobe的商场份额简直达到了近90%。

在CRM解决方案中可以看到相同的寡头独占,Salesforce、Microsoft Dynamics和Oracle在出售人员自动化和效劳应用程序中具有约70%的SaaS收入,而Adobe、Oracle和Salesforce则具有接近70% SaaS营销自动化的商场份额。

寡头独占并不是一件坏事,只需云效劳商持续加码竞赛,用户将从较低的价格中获益,但这样也可能导致消*影响。

据Forrester说:“如果这些公司团体赞同(隐含地或明确地)进步价格或为坚持*大化赢利而疏忽改进产品,客户将是终究的受害者。”

分析师以为,公有云渠道和桌面应用程序现已有了寡头独占式的集中。但是,像CRM、电子收购、供应链办理、人力资源办理体系等范畴格式还不稳定,电子商务和FMS范畴也需求很长一段时间才干呈现寡头。

联璧港兼提供商、服务商与渠道商身份为一体,无论你是用户还是开发者,在这里,你可以得到一切你想要的SaaS,也能够轻松上传优质的SaaS产品。SaaS的未来,联璧港将带你一起领略。SaaS平台哪家好?

转载于:https://www.cnblogs.com/viker/p/7608190.html

替换字符串中的括号内容

替换字符串中的括号内容

原题指路

替换字符串中的括号内容

题目描述
给你一个字符串 s ,它包含一些括号对,每个括号中包含一个 非空 的键。

比方说,字符串 “(name)is(age)yearsold” 中,有 两个 括号对,分别包含键 “name” 和 “age” 。
你知道许多键对应的值,这些关系由二维字符串数组 knowledge 表示,其中 knowledge[i] = [keyi, valuei] ,表示键 keyi 对应的值为 valuei 。
你需要替换 所有 的括号对。当你替换一个括号对,且它包含的键为 keyi 时,你需要:

将 keyi 和括号用对应的值 valuei 替换。
如果从 knowledge 中无法得知某个键对应的值,你需要将 keyi 和括号用问号 “?” 替换(不需要引号)。
knowledge 中每个键*多只会出现一次。s 中不会有嵌套的括号。
请你返回替换 所有 括号对后的结果字符串。

解题思路%title插图%num

其实这道题可能本意是自己建个哈希表来加速查找(因为*次暴力没过QAQ),但是……我偷懒直接建了个字典来查找,四舍五入也就是用的哈希……

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

代码
class Solution:
def evaluate(self, s: str, knowledge: list[list[str]]) -> str:
res = []
flag = 0
dict = {}
for k in knowledge:
dict[k[0]] = k[1]
for i, ch in enumerate(s):
if flag:
if ch == ‘)’:
flag = 0
keykey = “”.join(key)
if keykey in dict.keys():
res.append(dict[keykey])
else:
res.append(“?”)
else:
key.append(ch)
elif ch == ‘(‘:
flag = 1
key = []
else:
res.append(ch)
return “”.join(res)

 

Nutanix是超融合厂商?原来我们都误会了……

Nutanix是一家超融合厂商吗?是,也不是。

中国的很多用户在初次接触Nutanix公司时,它已经在全球的超融合市场上声誉鹊起,并且被奉为超融合的鼻祖,所以人们先入为主地认为,Nutanix就是一家超融合厂商。

作为一个新的细分产品市场的领导者,Nutanix当然也乐得以超融合作为一个理想的切入点,在云基础架构领域赚得“*桶金”,所以也就欣欣然接受了超融合这个标签。

随着云计算应用的快速普及,以及企业数字化转型逐渐走向深入,人们越来越多地重复这样一句话——不忘初心。那么,Nutanix的初心又是什么呢?

“在公司创立之初,我们就一直想将软件定义的思路、以AWS为代表的新型的公有云服务模式、苹果公司产品所体现的令人愉悦的体验,全部带入企业级应用市场,而超融合只不过是实现这一愿景的*步而已。”Nutanix中国区董事总经理陈满恒如是说。

说得更简单直白一些,Nutanix意在企业云市场,超融合只不过是在打地基。在中国,超融合市场还在持续升温。Nutanix当然不会放弃这一市场,只不过其重点已经开始向整个企业云市场倾斜,而且要为用户提供更多样化的选择。用现在*流行的一个词来形容,Nutanix在“转型”。从2009年成立至今,Nutanix已经褪去了初创公司的青涩和单纯“技术控”的气质,正在努力搭建自己的企业云商业帝国。

1 由硬变软

在*近一次Nutanix财报电话会议上,Nutanix公司首席执行官Dheeraj Pandey表示,未来公司将更多地采取以软件为中心的策略应对市场的变化。Nutanix公司首席财务官Duston Williams也表达了相同的看法:“今天的Nutanix是一家软件公司,或者更准确地说是一家企业云操作系统公司。”

毫无疑问,Nutanix在转型,从大多数人认为的超融合厂商走向更加广阔的企业云市场,从提供单纯的一体机解决方案演变为一个以软件为核心的多面手。

%title插图%num

Nutanix中国区董事总经理陈满恒

从2017年10月20日Nutanix正式宣布对陈满恒的任命到现在,仅仅几个月的时间,陈满恒已经深刻感受到了公司的变化。“我刚加盟公司时,公司的股票价格是21美元,而昨天股价已经飙升至36美元,增长了近80%。”陈满恒在2018年1月23日举行的媒体会上举例说。作为一家软件公司,Nutanix的“新身份”赢得了更多关注和肯定。

Nutanix的公开数据显示,公司FY18 Q1的收入为2.76亿美元,增长近50%,而中国市场的业绩增长更快。公司中国团队现有六七十人,而公司给陈满恒下达的任务是在一年半内将中国团队的人员规模再扩大一倍。“除了不断增强销售和售后服务能力以外,我们希望在中国拥有一个更加健康、平稳的组织架构。”陈满恒表示。

虽然超融合让人们认识并熟悉了Nutanix,但是对于现在的Nutanix来说,超融合市场已经有些施展不开。“以前,我们提供的超融合解决方案通常与硬件绑定,但是现在,我们要坚定地实现软硬件的分离,为用户提供更多的选择。对于我们销售纯软件解决方案,整个业界都十分看好。”

如果说从超融合到企业云是Nutanix的*次跃升,那么从一体化解决方案到纯软件的销售则是Nutanix的第二次跃升,Nutanix在软件方面的独特性和价值将得到充分释放。

“我们不会放弃超融合市场。”陈满恒再次强调,不过他话锋一转,“其实,广大客户更认可我们在企业云操作系统上的能力。我们也希望给用户更多的选择。适应不同的应用场景,用户既可以选择一体机,也可以采用纯软件。”

以前,Nutanix对硬件的要求确实非常苛刻,尤其是在选择硬件合作伙伴时甚至可以用挑剔两个字来形容。这是从保证产品的高性能和稳定性的角度考虑。现在,随着产品和技术趋于稳定和成熟,Nutanix一方面希望能够更加充分地发挥自己在软件方面的特长,另一方面也是为满足不同用户的需求,所以在销售层面变得更加灵活。陈满恒表示,未来的Nutanix会更加开放。2017年中,Nutanix与IBM达成了一项多年期合作计划,Nutanix的企业云平台软件将与IBM Power Systems相结合,为大型企业提供针对关键工作负载的超融合一站式解决方案。据说在亚太区,双方合作的*单就在中国。

据陈满恒介绍,从2月1日开始,Nutanix将正式在全球销售纯软件产品,而中国市场将从今年下半年开始销售纯软件产品。

2 从超融合到企业云

“从公司诞生之日起,我们的目标只有一个,那就是将云服务的种种益处带到企业级市场。”陈满恒表示,“云基础架构*终会变得透明。用户不必关心基础架构,他们的业务可以即插即用。”

谈到云计算的发展趋势,Nutanix中国区技术总监夏峰表示,未来计算将无处不在,而且云也呈现出分布式的状态。一家企业可能拥有多种业态、多个数据中心、多个分支机构,而不同的企业都拥有自己的一套架构或体系,多云融合会是一种“新常态”。数据在哪里产生,存储、计算和分析就在哪里进行,一个通信基站、一辆汽车或一艘轮船都可能成为一个小的数据中心,拥有自己的计算和分析能力。边缘计算正在兴起。从某个角度说,边缘计算甚至可以和物联网划等号。

%title插图%num

针对这一趋势,Nutanix希望提供一个统一的云平台——企业云操作系统,覆盖从企业的核心云到分布式云,从而简化云的管理和应用。“简洁而优雅,这就是我们的产品特色和优势。”夏峰这样说。

超融合是一个“交钥匙”的解决方案,它更容易让用户接受和掌握。作为开启企业云之旅的*步,超融合为企业云化奠定了基础。不过,超融合毕竟不是云,从超融合到分布式云,中间还有很多台阶要迈。

从*底层的超融合架构,到Acropolis虚拟化框架,再到Prism管理框架,直到多云管理,Nutanix提供的是“一键直达,多云融合”的上云解决方案和平台。“在这个过程中,超融合只是一个工具,而不是目的,企业云才是*终的目标。”夏峰表示。

Nutanix一直在进行快速的产品迭代,不断丰富超融合产品的功能,将人工智能算法融入产品中,提供对不同虚拟化软件的支持,而不是将用户限定在某一个虚拟化软件上,并与多个公有云对接,实现多云管理等。2017年6月,Nutanix宣布与谷歌云(Google Cloud)建立战略联盟,方便双方的企业客户能够用统一的公有云服务来部署和管理云计算应用和传统企业用户程序,Nutanix环境与Google Cloud Platform(GCP)也无缝融合在一起。

Nutanix为企业用户提供了一条上云的捷径:企业用户可以先从传统架构迁移到Nutanix超融合架构,然后再迁移到Nutanix AHV,实现全栈自动化,之后可以尝试用Nutanix Calm进行应用生命周期管理,当用户在核心数据中心里全部采用了Nutanix的产品后,就可以进行下一步,向分布式云过渡,*终实现智能边缘云。

“我们定位在企业云市场,致力于为用户提供单一的云操作系统、一致的应用体验。我们要为用户提供不同的选择,比如对多种虚拟化软件的支持,可以是VMware、微软、思杰或Nutanix AHV,而不是将用户绑定在某一个平台上。”陈满恒表示,“Nutanix从一开始就想把公有云的体验带给企业级用户。我们先用超融合解决存储和信息的问题,然后慢慢向企业云扩展,循序渐进。”

2018年中,Nutanix在全球还将正式推出Xi Cloud灾难恢复服务。

对于超融合能够做什么,大家已经十分清楚。对于Nutanix能够给企业云市场带来什么样的变革,人们更多地是期待,当然也会有疑问,这可能需要一个慢慢认知和转变的过程。Nutanix已经说得很明白,无论用户使用哪种云,它都可以提供一致的体验。现在,Nutanix需要用更多成功的案例证明给中国用户看。

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

原文链接:https://blog.csdn.net/Bmo40mqfG249H/article/details/79157633

怎么创建服务器集群?

一个集群 (cluster)指容器运行所需要的云资源组合,关联了若干云服务器节点、负载均衡等云资源。
通过多种方式创建一个集群:

方法一:
创建一个集群,并同时创建若干个云服务器。
您可以通过容器服务直接创建一个包含若干个新云服务器的集群。

方法二:
创建一个零节点的集群并添加已有的云服务器。
创建一个零节点的集群。
如果您已经在云服务器 ECS 上购买了若干个云服务器,可以在容器服务上创建一个零节点的集群。
操作方式同 方法一,您只需要选择添加已有节点。
添加已有的云服务器。
您可以通过以下两种方法将已有云服务器添加到容器服务中。
重置云服务器的镜像,将其自动加入集群。
此种方式会重置云服务器的镜像和系统盘,需要谨慎。但是这种方式加入的服务器比较干净。
在云服务器上执行脚本,将云服务器手动加入集群。
此种方式适合于不希望重置云服务器的镜像。

Tomcat配置本地文件【图片】服务器

一、简介
一般情况下,我们项目开发时,在本地环境下,把这个tomcat作为项目服务器,就是把项目放在tomcat上面跑。这个是tomcat用的*多的地方,分享一下,但是其实Tomcat还可以作为其他来用,这里要讲的就是用tomcat来配置本地的文件服务器。下面是步骤:

二、配置步骤
【1】下载一个tomcat文件版,放在本地,比如apache-tomcat-8.0.53;

【2】然后找到tomcat的conf文件夹下的server.xml文件:
%title插图%num

【3】在server.xml中加入下面配置 :

%title插图%num

【4】代码如下:

<Service name=”newtest”>
<!–分配8089端口 –>
<Connector port=”8089″
protocol=”HTTP/1.1″
connectionTimeout=”20000″
URIEncoding=”GBK”
redirectPort=”8443″ />

<Engine name=”newtest” defaultHost=”localhost”>
<!–name为项目访问地址 此配置的访问为http://localhost:8089 appBase配置tomcat下wabapps下的路径–>
<Host name=”localhost” appBase=”F://Tomcat6//apache-tomcat-6.0.29//webapps” unpackWARs=”true” autoDeploy=”true”
xmlValidation=”false” xmlNamespaceAware=”false”>

<!–资源地址–> <!– 就是访问http://localhost:8089这个地址就是到E://TangRenFileServer//images这个目录下 –>
<Context path=”” docBase=”E://TangRenFileServer//images” debug=”0″ reloadable=”false”/>
</Host>
</Engine>
</Service>
【5】注意了,这个时候,访问http://localhost:8089这个地址就是到E://TangRenFileServer//images这个本地目录下

应用服务器和数据库服务器有什么区别

数据库服务器一般都装有数据库如oracle,mssql,mysql等,如:oracle的linux服务器,

应用服务器是你的应用得服务器,提供应用服务,如你的j2ee中间件:基于jboss,weblogic等的应用,也可以是自己的网络应用服务器,接口服务器是提供给第三方调用的服务,主要是为了我们自己的应用得安全性,所以我们只把能供给第三方调用的东西封装在接口服务器

数据服务器和应用服务器有什么区别?
不知道你对数据库了解不了解!数据库服务器简单点:还不好和你解释!

数据库服务器

数据库:存储数据的应用软件

服务器:公共的意思了!

一台机子!安装一个软件,你可以用,别人也可以用!就像你的电脑一样可以有多个用户一样,你可以用你的用户名登陆,别人可以有另一个用户名登陆,就是说可以有多个人用,但是每个人又是独立的!(当然这个还是有点区别的!)

首先,根据你应用环境的不同,需要的数据库服务器也不同,一般来说,如果数据库服务器需要连接的客户端多、并且是不同权限组的客户端的话需要网络接口比较多的,除此之外,数据库服务器的处理器性能要求比较高,因为其要进行频繁的操作,内存要求大,加快数据存取速度。

应用服务器相对而言要求低一些,如果是FTP服务器的话网卡的速率要求要高,起码是千兆的,网页服务器对于网卡的速率也同样有较高的要求,但对于处理器性能要求就不那么高了。

其次,后面涉及到产品硬件这块也是非常重要的。

应用服务器位于网络和数据库之间,但是应用服务器实际上是做什么的?

应用程序服务器是为应用程序提供业务逻辑的。它是基于组件的,位于以服务器为中心的架构的中间件。

这个架构通常是一个主要的基于Web的界面。中间件是业务逻辑所在的应用服务器。而第三层,后端是负责数据库的服务器。应用程序服务器充当用户和数据库之间的交互。

应用服务器通过各种协议向客户端应用程序打开业务逻辑。它还可以包括计算机,web服务器或其他应用服务器上的图形用户界面。业务逻辑通过组件API。它还管理自己的资源以及执行安全性,事务处理,资源和连接池以及消息传递。

对于高端要求,应用服务器往往具有高可用性监控,集群,负载平衡,集成冗余和高性能分布式应用服务,并支持复杂的数据库访问。

为什么要使用应用服务器?有什么好处?
当你需要与现有数据库和服务器(如Web服务器)集成时,应使用应用程序服务器。

它可以通过启用集中式方法来提供应用程序更新和升级来提供数据和代码的完整性。

可伸缩性是使用应用服务器的另一个原因和好处。应用程序服务器可以与数据库连接。这意味着企业可以扩展Web服务器群,而不需要增加数据库连接的数量。

%title插图%num

另一个好处是安全。从网页到数据库的直接链接如果暴露,可导致SQL注入攻击基础架构。通过单独的数据访问层执行数据验证和/或显示业务逻辑,可以确保以Web表单输入的文本不被用作SQL调用。通过集中身份验证过程以及数据访问管理,还可以提高安全性。

它还可以通过对网络流量进行限制来提高对性能要求高的应用程序的性能。

它与其他类型服务器有何区别?
应用程序服务器与Web服务器不同,因为前者通过多种协议处理向应用程序提供业务逻辑,而Web服务器响应并处理HTTP请求;它托管一个网站并存储静态内容,如图像,CSS,JavaScript和HTML页面。虽然Web服务器可能不支持事务或数据库连接,但它可能具有容错和可扩展性功能,如负载平衡,缓存和集群。

%title插图%num

它与数据库服务器不同,因为该服务器执行诸如数据分析,存储,数据处理,归档以及其他数据管理相关任务之类的任务。数据库服务器使用诸如ODBC,JDBC等协议。他们还将托管数据库,如Oracle,SQL Server,MySQL等。

Python 正则表达式(模式匹配)

Python 正则表达式(模式匹配)

 

1.  Python正则式的基本用法

1.1基本规则

1.2重复

1.2.1*小匹配与精确匹配

1.3前向界定与后向界定

1.4组的基本知识

2.  re模块的基本函数

2.1使用compile加速

2.2 matchsearch

2.3 finditer

2.4 字符串的修改与替换

3.  更深入的了解re的组与对象

3.1编译后的Pattern对象

3.2 组与Match对象

3.2.1组的名字与序号

3.2.2 Match对象的方法

4.  更多的资料

 

初学Python,对Python的文字处理能力有很深的印象,除了str对象自带的一些方法外,就是正则表达式这个强大的模块了。但是对于初学者来说,要用好这个功能还是有点难度,我花了好长时间才摸出了点门道。由于我记性不好,很容易就忘事,所以还是写下来比较好一些,同时也可以加深印象,整理思路。

由于我是初学,所以肯定会有些错误,还望高手不吝赐教,指出我的错误。

1 Python正则式的基本用法

Python的正则表达式的模块是 ‘re’,它的基本语法规则就是指定一个字符序列,比如你要在一个字符串s=’123abc456’ 中查找字符串 ’abc’,只要这样写:

>>> import re

>>> s=’123abc456eabc789′

>>> re.findall(r’abc’,s)

结果就是:

[‘abc’, ‘abc’]

这里用到的函数 ”findall(rule , target [,flag] )” 是个比较直观的函数,就是在目标字符串中查找符合规则的字符串。*个参数是规则,第二个参数是目标字符串,后面还可以跟一个规则选项(选项功能将在compile函数的说明中详细说明)。返回结果结果是一个列表,中间存放的是符合规则的字符串。如果没有符合规则的字符串被找到,就返回一个列表。

 

为什么要用r’ ..‘字符串(raw字符串)? 由于正则式的规则也是由一个字符串定义的,而在正则式中大量使用转义字符’/’,如果不用raw字符串,则在需要写一个’/’的地方,你必须得写成’//’,那么在要从目标字符串中匹配一个’/’的时候,你就得写上4’/’成为’’!这当然很麻烦,也不直观,所以一般都使用r’’来定义规则字符串。当然,某些情况下,可能不用raw字符串比较好。

 

以上是个*简单的例子。当然实际中这么简单的用法几乎没有意义。为了实现复杂的规则查找,re规定了若干语法规则。它们分为这么几类:

功能字符     ‘.’ ‘*’ ‘+’ ‘|’ ‘?’ ‘^’ ‘$’ ‘/’ 等,它们有特殊的功能含义。特别是’/’字符,它是转义引导符号,跟在它后面的字符一般有特殊的含义。

规则分界符: ‘[‘ ‘]’ ‘’ ‘’ ‘{‘ ‘}’ 等,也就是几种括号了。

预定义转义字符集: “/d”  “/w” “/s” 等等,它们是以字符’/’开头,后面接一个特定字符的形式,用来指示一个预定义好的含义。

其它特殊功能字符: ’#’ ‘!’ ‘:’ ‘-‘等,它们只在特定的情况下表示特殊的含义,比如(?# …)就表示一个注释,里面的内容会被忽略。

 

下面来一个一个的说明这些规则的含义,不过说明的顺序并不是按照上面的顺序来的,而是我认为由浅入深,由基本到复杂的顺序来编排的。同时为了直观,在说明的过程中尽量多举些例子以方便理解。

1.1 基本规则

 

‘[‘  ‘]’ 字符集合设定符

首先说明一下字符集合设定的方法。由一对方括号括起来的字符,表明一个字符集合,能够匹配包含在其中的任意一个字符。比如 [abc123],表明字符’a’ ‘b’ ‘c’ ‘1’ ‘2’ ‘3’都符合它的要求。可以被匹配。

’[‘ ‘]’中还可以通过 ’-‘ 减号来指定一个字符集合的范围,比如可以用[a-zA-Z]来指定所以英文字母的大小写,因为英文字母是按照从小到大的顺序来排的。你不可以把大小的顺序颠倒了,比如写成[z-a]就不对了。

如果在’[‘ ‘]’里面的开头写一个 ‘^’ 号,则表示取非,即在括号里的字符都不匹配。如[^a-zA-Z]表明不匹配所有英文字母。但是如果 ‘^’不在开头,则它就不再是表示取非,而表示其本身,如[a-z^A-Z]表明匹配所有的英文字母和字符’^’

 

‘|’    或规则

将两个规则并列起来,以‘|’连接,表示只要满足其中之一就可以匹配。比如

[a-zA-Z]|[0-9] 表示满足数字或字母就可以匹配,这个规则等价于 [a-zA-Z0-9]

注意:关于’|’要注意两点:

*,           它在’[‘ ‘]’之中不再表示或,而表示他本身的字符。如果要在’[‘ ‘]’外面表示一个’|’字符,必须用反斜杠引导,即 ’/|’ ;

第二,           它的有效范围是它两边的整条规则,比如‘dog|cat’匹配的是‘dog’’cat’,而不是’g’’c’。如果想限定它的有效范围,必需使用一个无捕获组 ‘(?: )’包起来。比如要匹配 ‘I have a dog’’I have a cat’,需要写成r’I have a (?:dog|cat)’ ,而不能写成 r’I have a dog|cat’

>>> s = ‘I have a dog , I have a cat’

>>> re.findall( r’I have a (?:dog|cat)’ , s )

[‘I have a dog’, ‘I have a cat’]                #正如我们所要的

下面再看看不用无捕获组会是什么后果:

>>> re.findall( r’I have a dog|cat’ , s )

[‘I have a dog’, ‘cat’]                                   #它将’I have a dog’ ’cat’当成两个规则了

至于无捕获组的使用,后面将仔细说明。这里先跳过。

 

‘.’    匹配所有字符

匹配除换行符’/n’外的所有字符。如果使用了’S’选项,匹配包括’/n’的所有字符。

       例:

       >>> s=’123 /n456 /n789’

       >>> findall(r‘.+’,s)

       [‘123’, ‘456’, ‘789’]

       >>> re.findall(r‘.+’ , s , re.S)

       [‘123/n456/n789’]

 

‘^’’$’ 匹配字符串开头和结尾

注意’^’不能在‘[ ]’中,否则含意就发生变化,具体请看上面的’[‘ ‘]’说明。 在多行模式下,它们可以匹配每一行的行首和行尾。具体请看后面compile函数说明的’M’选项部分

 

‘/d’ 匹配数字

这是一个以’/’开头的转义字符,’/d’表示匹配一个数字,即等价于[0-9]

‘/D’ 匹配非数字

这个是上面的反集,即匹配一个非数字的字符,等价于[^0-9]。注意它们的大小写。下面我们还将看到Python的正则规则中很多转义字符的大小写形式,代表互补的关系。这样很好记。

 

‘/w’ 匹配字母和数字

匹配所有的英文字母和数字,即等价于[a-zA-Z0-9]

‘/W’ 匹配非英文字母和数字

’/w’的补集,等价于[^a-zA-Z0-9]

 

‘/s’ 匹配间隔符

即匹配空格符、制表符、回车符等表示分隔意义的字符,它等价于[ /t/r/n/f/v]。(注意*前面有个空格)

‘/S’ 匹配非间隔符

即间隔符的补集,等价于[^ /t/r/n/f/v]

 

‘/A’ 匹配字符串开头

匹配字符串的开头。它和’^’的区别是,’/A’只匹配整个字符串的开头,即使在’M’模式下,它也不会匹配其它行的很首。

‘/Z’ 匹配字符串结尾

匹配字符串的结尾。它和’$’的区别是,’/Z’只匹配整个字符串的结尾,即使在’M’模式下,它也不会匹配其它各行的行尾。

例:

>>> s= ’12 34/n56 78/n90′

>>> re.findall( r’^/d+’ , s , re.M )          #匹配位于行首的数字

[’12’, ’56’, ’90’]

>>> re.findall( r’/A/d+’, s , re.M )        #匹配位于字符串开头的数字

[’12’]

>>> re.findall( r’/d+$’ , s , re.M )          #匹配位于行尾的数字

[’34’, ’78’, ’90’]

>>> re.findall( r’/d+/Z’ , s , re.M )        #匹配位于字符串尾的数字

[’90’]

 

‘/b’ 匹配单词边界

它匹配一个单词的边界,比如空格等,不过它是一个‘0’长度字符,它匹配完的字符串不会包括那个分界的字符。而如果用’/s’来匹配的话,则匹配出的字符串中会包含那个分界符。

例:

>>> s =  ‘abc abcde bc bcd’

>>> re.findall( r’/bbc/b’ , s )         #匹配一个单独的单词 ‘bc’ ,而当它是其它单词的一部分的时候不匹配

[‘bc’]                                           #只找到了那个单独的’bc’

>>> re.findall( r’/sbc/s’ , s )          #匹配一个单独的单词 ‘bc’

[‘ bc ‘]                                         #只找到那个单独的’bc’,不过注意前后有两个空格,可能有点看不清楚

‘/B’ 匹配非边界

’/b’相反,它只匹配非边界的字符。它同样是个0长度字符。

接上例:

>>> re.findall( r’/Bbc/w+’ , s )     #匹配包含’bc’但不以’bc’为开头的单词

[‘bcde’]                                       #成功匹配了’abcde’中的’bcde’,而没有匹配’bcd’

 

‘(?:)’ 无捕获组

当你要将一部分规则作为一个整体对它进行某些操作,比如指定其重复次数时,你需要将这部分规则用’(?:’ ‘)’把它包围起来,而不能仅仅只用一对括号,那样将得到*对出人意料的结果。

例:匹配字符串中重复的’ab’

>>> s=’ababab abbabb aabaab’

>>> re.findall( r’/b(?:ab)+/b’ , s )

[‘ababab’]

如果仅使用一对括号,看看会是什么结果:

>>> re.findall( r’/b(ab)+/b’ , s )

[‘ab’]

这是因为如果只使用一对括号,那么这就成为了一个组(group)。组的使用比较复杂,将在后面详细讲解。

 

‘(?# )’ 注释

Python允许你在正则表达式中写入注释,在’(?#’ ‘)’之间的内容将被忽略。

 

(?iLmsux) 编译选项指定

Python的正则式可以指定一些选项,这个选项可以写在findallcompile的参数中,也可以写在正则式里,成为正则式的一部分。这在某些情况下会便利一些。具体的选项含义请看后面的compile函数的说明。

此处编译选项’i’ 等价于IGNORECASE 等价于 LOCAL 等价于 MULTILINE 等价于 DOTALL 等价于 UNICODE  x 等价于 VERBOSE 

请注意它们的大小写。在使用时可以只指定一部分,比如只指定忽略大小写,可写为 ‘(?i)’,要同时忽略大小写并使用多行模式,可以写为 ‘(?im)’

另外要注意选项的有效范围是整条规则,即写在规则的任何地方,选项都会对全部整条正则式有效。

 

 

1.2 重复

正则式需要匹配不定长的字符串,那就一定需要表示重复的指示符。Python的正则式表示重复的功能很丰富灵活。重复规则的一般的形式是在一条字符规则后面紧跟一个表示重复次数的规则,已表明需要重复前面的规则一定的次数。重复规则有:

‘*’   0或多次匹配

表示匹配前面的规则0次或多次。

‘+’   1次或多次匹配

表示匹配前面的规则至少1次,可以多次匹配

例:匹配以下字符串中的前一部分是字母,后一部分是数字或没有的变量名字

>>> s = ‘ aaa bbb111 cc22cc 33dd ‘

>>> re.findall( r’/b[a-z]+/d*/b’ , s )             #必须至少1个字母开头,以连续数字结尾或没有数字

[‘aaa’, ‘bbb111’]

注意上例中规则前后加了表示单词边界的’/b’指示符,如果不加的话结果就会变成:

>>> re.findall( r’[a-z]+/d*’ , s )

[‘aaa’, ‘bbb111’, ‘cc22’, ‘cc’, ‘dd’]    #把单词给拆开了

大多数情况下这不是我们期望的结果。

 

‘?’   01次匹配

只匹配前面的规则0次或1次。

例,匹配一个数字,这个数字可以是一个整数,也可以是一个科学计数法记录的数字,比如12310e3都是正确的数字。

>>> s = ‘ 123 10e3 20e4e4 30ee5 ‘

>>> re.findall( r’ /b/d+[eE]?/d*/b’ , s )

[‘123′, ’10e3’]

它正确匹配了12310e3,正是我们期望的。注意前后的’/b’的使用,否则将得到不期望的结果。

 

1.2.1 精确匹配和*小匹配

Python正则式还可以精确指定匹配的次数。指定的方式是

‘{m}’      精确匹配m

‘{m,n}’   匹配*少m次,*多n次。(n>m)

如果你只想指定一个*少次数或只指定一个*多次数,你可以把另外一个参数空起来。比如你想指定*少3次,可以写成 {3,} (注意那个逗号),同样如果只想指定*大为5次,可以写成{5},也可以写成{0,5}

例 寻找下面字符串中

a3位数

b: 2位数到4位数

c: 5位数以上的数

d: 4位数以下的数

>>> s= ‘ 1 22 333 4444 55555 666666 ‘

>>> re.findall( r’/b/d{3}/b’ , s )            # a3位数

[‘333’]

>>> re.findall( r’/b/d{2,4}/b’ , s )         # b: 2位数到4位数

[’22’, ‘333’, ‘4444’]

>>> re.findall( r’/b/d{5,}/b’, s )           # c: 5位数以上的数

[‘55555’, ‘666666’]

>>> re.findall( r’/b/d{1,4}/b’ , s )         # 4位数以下的数

[‘1′, ’22’, ‘333’, ‘4444’]

 

‘*?’ ‘+?’ ‘??’ *小匹配

‘*’ ‘+’ ‘?’通常都是尽可能多的匹配字符。有时候我们希望它尽可能少的匹配。比如一个c语言的注释 ‘/* part 1 */ /* part 2 */’,如果使用*大规则:

>>> s =r ‘/* part 1 */ code /* part 2 */’

>>> re.findall( r’//*.*/*/’ , s )

[‘/* part 1 */ code /* part 2 */’]

结果把整个字符串都包括进去了。如果把规则改写成

>>> re.findall( r’//*.*?/*/’ , s )                    #*后面加上?,表示尽可能少的匹配

[‘/* part 1 */’, ‘/* part 2 */’]

结果正确的匹配出了注释里的内容

 

1.3   前向界定与后向界定

有时候需要匹配一个跟在特定内容后面的或者在特定内容前面的字符串,Python提供一个简便的前向界定和后向界定功能,或者叫前导指定和跟从指定功能。它们是:

‘(?<=…)’ 前向界定

括号中’…’代表你希望匹配的字符串的前面应该出现的字符串。

‘(?=…)’  后向界定

括号中的’…’代表你希望匹配的字符串后面应该出现的字符串。

例: 你希望找出c语言的注释中的内容,它们是包含在’/*’’*/’之间,不过你并不希望匹配的结果把’/*’’*/’也包括进来,那么你可以这样用:

>>> s=r’/* comment 1 */  code  /* comment 2 */’

>>> re.findall( r’(?<=//*).+?(?=/*/)’ , s )

[‘ comment 1 ‘, ‘ comment 2 ‘]

注意这里我们仍然使用了*小匹配,以避免把整个字符串给匹配进去了。

要注意的是,前向界定括号中的表达式必须是常值,也即你不可以在前向界定的括号里写正则式。比如你如果在下面的字符串中想找到被字母夹在中间的数字,你不可以用前向界定:

例:

>>> s = ‘aaa111aaa , bbb222 , 333ccc ‘

>>> re.findall( r’(?<=[a-z]+)/d+(?=[a-z]+)’ , s )          # 错误的用法

它会给出一个错误信息:

error: look-behind requires fixed-width pattern

 

不过如果你只要找出后面接着有字母的数字,你可以在后向界定写正则式:

>>> re.findall( r’/d+(?=[a-z]+)’, s )

[‘111’, ‘333’]

如果你一定要匹配包夹在字母中间的数字,你可以使用组(group)的方式

>>> re.findall (r'[a-z]+(/d+)[a-z]+’ , s )

[‘111’]

组的使用将在后面详细讲解。

 

除了前向界定前向界定和后向界定外,还有前向非界定和后向非界定,它的写法为:

‘(?<!…)’前向非界定

只有当你希望的字符串前面不是’…’的内容时才匹配

‘(?!…)’后向非界定

只有当你希望的字符串后面不跟着’…’内容时才匹配。

接上例,希望匹配后面不跟着字母的数字

>>> re.findall( r’/d+(?!/w+)’ , s )

[‘222’]

注意这里我们使用了/w而不是像上面那样用[a-z],因为如果这样写的话,结果会是:

>>> re.findall( r’/d+(?![a-z]+)’ , s )

[’11’, ‘222’, ’33’]

这和我们期望的似乎有点不一样。它的原因,是因为’111’’222’中的前两个数字也是满足这个要求的。因此可看出,正则式的使用还是要相当小心的,因为我开始就是这样写的,看到结果后才明白过来。不过Python试验起来很方便,这也是脚本语言的一大优点,可以一步一步的试验,快速得到结果,而不用经过烦琐的编译、链接过程。也因此学习Python就要多试,跌跌撞撞的走过来,虽然曲折,却也很有乐趣。

 

1.4 组的基本知识

上面我们已经看过了Python的正则式的很多基本用法。不过如果仅仅是上面那些规则的话,还是有很多情况下会非常麻烦,比如上面在讲前向界定和后向界定时,取夹在字母中间的数字的例子。用前面讲过的规则都很难达到目的,但是用了组以后就很简单了。

‘(‘’)’       无命名组

*基本的组是由一对圆括号括起来的正则式。比如上面匹配包夹在字母中间的数字的例子中使用的(/d+),我们再回顾一下这个例子:

>>> s = ‘aaa111aaa , bbb222 , 333ccc ‘

>>> re.findall (r'[a-z]+(/d+)[a-z]+’ , s )

[‘111’]

可以看到findall函数只返回了包含在’()’中的内容,而虽然前面和后面的内容都匹配成功了,却并不包含在结果中。

 

除了*基本的形式外,我们还可以给组起个名字,它的形式是

‘(?P<name>…)’ 命名组

‘(?P’代表这是一个Python的语法扩展’<…>’里面是你给这个组起的名字,比如你可以给一个全部由数字组成的组叫做’num’,它的形式就是’(?P<num>/d+)’。起了名字之后,我们就可以在后面的正则式中通过名字调用这个组,它的形式是

‘(?P=name)’ 调用已匹配的命名组

要注意,再次调用的这个组是已被匹配的组,也就是说它里面的内容是和前面命名组里的内容是一样的。

我们可以看更多的例子:请注意下面这个字符串各子串的特点。

>>> s=’aaa111aaa,bbb222,333ccc,444ddd444,555eee666,fff777ggg’

我们看看下面的正则式会返回什么样的结果:

>>> re.findall( r'([a-z]+)/d+([a-z]+)’ , s )             # 找出中间夹有数字的字母

[(‘aaa’, ‘aaa’), (‘fff’, ‘ggg’)]

>>> re.findall( r ‘(?P<g1>[a-z]+)/d+(?P=g1)’ , s ) #找出被中间夹有数字的前后同样的字母

[‘aaa’]

>>> re.findall( r'[a-z]+(/d+)([a-z]+)’ , s )             #找出前面有字母引导,中间是数字,后面是字母的字符串中的中间的数字和后面的字母

[(‘111’, ‘aaa’), (‘777’, ‘ggg’)]

 

我们可以通过命名组的名字在后面调用已匹配的命名组,不过名字也不是必需的。

‘/number’             通过序号调用已匹配的组

正则式中的每个组都有一个序号,序号是按组从左到右,从1开始的数字,你可以通过下面的形式来调用已匹配的组

比如上面找出被中间夹有数字的前后同样的字母的例子,也可以写成:

>>> re.findall( r’([a-z]+)/d+/1’ , s )

[‘aaa’]

结果是一样的。

我们再看一个例子

>>> s=’111aaa222aaa111 , 333bbb444bb33′

>>> re.findall( r'(/d+)([a-z]+)(/d+)(/2)(/1)’ , s )           #找出完全对称的 数字-字母-数字-字母-数字 中的数字和字母

[(‘111’, ‘aaa’, ‘222’, ‘aaa’, ‘111’)]

 

Python2.4以后的re模块,还加入了一个新的条件匹配功能

‘(?(id/name)yes-pattern|no-pattern)’ 判断指定组是否已匹配,执行相应的规则

这个规则的含义是,如果id/name指定的组在前面匹配成功了,则执行yes-pattern的正则式,否则执行no-pattern的正则式。

举个例子,比如要匹配一些形如 usr@mail 的邮箱地址,不过有的写成< usr@mail >即用一对<>括起来,有点则没有,要匹配这两种情况,可以这样写

>>> s='<usr1@mail1>  usr2@maill2′

>>> re.findall( r'(<)?/s*(/w+@/w+)/s*(?(1)>)’ , s )

[(‘<‘, ‘usr1@mail1’), (”, ‘usr2@maill2’)]

不过如果目标字符串如下

>>> s='<usr1@mail1>  usr2@maill2 <usr3@mail3   usr4@mail4>  < usr5@mail5 ‘

而你想得到要么由一对<>包围起来的一个邮件地址,要么得到一个没有被<>包围起来的地址,但不想得到一对<>中间包围的多个地址或不完整的<>中的地址,那么使用这个式子并不能得到你想要的结果

>>> re.findall( r'(<)?/s*(/w+@/w+)/s*(?(1)>)’ , s )

[(‘<‘, ‘usr1@mail1’), (”, ‘usr2@maill2’), (”, ‘usr3@mail3’), (”, ‘usr4@mail4’), (”, ‘usr5@mail5’)]

它仍然找到了所有的邮件地址。

想要实现这个功能,单纯的使用findall有点吃力,需要使用其它的一些函数,比如matchsearch函数,再配合一些控制功能。这部分的内容将在下面详细讲解。

 

小结:以上基本上讲述了Python正则式的语法规则。虽然大部分语法规则看上去都很简单,可是稍不注意,仍然会得到与期望大相径庭的结果,所以要写好正则式,需要仔细的体会正则式规则的含义后不同规则之间细微的差别。

详细的了解了规则后,再配合后面就要介绍的功能函数,就能*大的发挥正则式的威力了。

 

2 re模块的基本函数

在上面的说明中,我们已经对re模块的基本函数 ‘findall’很熟悉了。当然如果光有findall的话,很多功能是不能实现的。下面开始介绍一下re模块其它的常用基本函数。灵活搭配使用这些函数,才能充分发挥Python正则式的强大功能。

首先还是说下老熟人findall函数吧

findall(rule , target [,flag] )

在目标字符串中查找符合规则的字符串。

*个参数是规则,第二个参数是目标字符串,后面还可以跟一个规则选项(选项功能将在compile函数的说明中详细说明)。

返回结果结果是一个列表,中间存放的是符合规则的字符串。如果没有符合规则的字符串被找到,就返回一个列表。

2.1 使用compile加速

compile( rule [,flag] )

将正则规则编译成一个Pattern对象,以供接下来使用。

*个参数是规则式,第二个参数是规则选项。

返回一个Pattern对象

直接使用findall ( rule , target )的方式来匹配字符串,一次两次没什么,如果是多次使用的话,由于正则引擎每次都要把规则解释一遍,而规则的解释又是相当费时间的,所以这样的效率就很低了。如果要多次使用同一规则来进行匹配的话,可以使用re.compile函数来将规则预编译,使用编译过返回的Regular Expression Object或叫做Pattern对象来进行查找。

>>> s=’111,222,aaa,bbb,ccc333,444ddd’

>>> rule=r’/b/d+/b’

>>> compiled_rule=re.compile(rule)

>>> compiled_rule.findall(s)

[‘111’, ‘222’]

可见使用compile过的规则使用和未编译的使用很相似。compile函数还可以指定一些规则标志,来指定一些特殊选项。多个选项之间用 |(位或)连接起来。

I      IGNORECASE 忽略大小写区别。

 

L   LOCAL  字符集本地化。这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符/w,在英文环境下,它代表[a-zA-Z0-9],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配“é”  “ç”加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

 

M    MULTILINE  多行匹配。在这个模式下’^’(代表字符串开头)’$’(代表字符串结尾)将能够匹配多行的情况,成为行首和行尾标记。比如

>>> s=’123 456/n789 012/n345 678’

>>> rc=re.compile(r’^/d+’)    #匹配一个位于开头的数字,没有使用M选项

>>> rc.findall(s)

[‘123’]             #结果只能找到位于*个行首的’123’

>>> rcm=re.compile(r’^/d+’,re.M)       #使用 M 选项

>>> rcm.findall(s)

[‘123’, ‘789’, ‘345’]  #找到了三个行首的数字

同样,对于’$’来说,没有使用M选项,它将匹配*后一个行尾的数字,即’678’,加上以后,就能匹配三个行尾的数字456 012678.

>>> rc=re.compile(r’/d+$’)

>>> rcm=re.compile(r’/d+$’,re.M)

>>> rc.findall(s)

[‘678’]

>>> rcm.findall(s)

[‘456’, ‘012’, ‘678’]

 

S     DOTALL       ‘.’号将匹配所有的字符。缺省情况下’.’匹配除换行符’/n’外的所有字符,使用这一选项以后,’.’就能匹配包括’/n’的任何字符了。

 

U   UNICODE       /w/W/b/B/d/D/s 和 /S都将使用Unicode

 

X     VERBOSE     这个选项忽略规则表达式中的空白,并允许使用’#’来引导一个注释。这样可以让你把规则写得更美观些。比如你可以把规则

>>> rc = re.compile(r/d+|[a-zA-Z]+“)       #匹配一个数字或者单词

使用X选项写成:

>>> rc = re.compile(r”””  # start a rule/d+                   # number| [a-zA-Z]+           # word“””, re.VERBOSE)在这个模式下,如果你想匹配一个空格,你必须用‘/ ‘的形式(‘/’后面跟一个空格)

 

 

2.2 matchsearch

match( rule , targetString [,flag] )

search( rule , targetString [,flag] )

(注:rematch search函数同compile过的Pattern对象的matchsearch函数的参数是不一样的。Pattern对象的matchsearch函数更为强大,是真正*常用的函数)

按照规则在目标字符串中进行匹配。

*个参数是正则规则,第二个是目标字符串,第三个是选项(同compile函数的选项)

返回:若成功返回一个Match对象,失败无返回

findall虽然很直观,但是在进行更复杂的操作时,就有些力不从心了。此时更多的使用的是matchsearch函数。他们的参数和findall是一样的,都是:

match( rule , targetString [,flag] )

search( rule , targetString [,flag] )

不过它们的返回不是一个简单的字符串列表,而是一个MatchObject (如果匹配成功的话).。通过操作这个matchObject,我们可以得到更多的信息。

需要注意的是,如果匹配不成功,它们则返回一个NoneType。所以在对匹配完的结果进行操作之前,你必需先判断一下是否匹配成功了,比如:

>>> m=re.match( rule , target )

>>> if m:                       #必需先判断是否成功

        doSomethin

这两个函数唯一的区别是:match从字符串的开头开始匹配,如果开头位置没有匹配成功,就算失败了;而search会跳过开头,继续向后寻找是否有匹配的字符串。针对不同的需要,可以灵活使用这两个函数。

关于match返回的MatchObject如果使用的问题,是Python正则式的精髓所在,它与组的使用密切相关。我将在下一部分详细讲解,这里只举个*简单的例子:

例:

>>> s= ‘Tom:9527 , Sharry:0003’

>>> m=re.match( r'(?P<name>/w+):(?P<num>/d+)’ , s )

>>> m.group()

‘Tom:9527’

>>> m.groups()

(‘Tom’, ‘9527’)

>>> m.group(‘name’)

‘Tom’

>>> m.group(‘num’)

‘9527’

 

2.3 finditer

finditer( rule , target [,flag] )

参数同findall

返回一个迭代器

finditer函数和findall函数的区别是,findall返回所有匹配的字符串,并存为一个列表,而finditer则并不直接返回这些字符串,而是返回一个迭代器。关于迭代器,解释起来有点复杂,还是看看例子把:

>>> s=’111 222 333 444’

>>> for i in re.finditer(r’/d+’ , s ):

        print i.group(),i.span()          #打印每次得到的字符串和起始结束位置

结果是

111 (0, 3)

222 (4, 7)

333 (8, 11)

444 (12, 15)

简单的说吧,就是finditer返回了一个可调用的对象,使用 for i in finditer()的形式,可以一个一个的得到匹配返回的 Match对象。这在对每次返回的对象进行比较复杂的操作时比较有用。

 

2.4 字符串的替换和修改

re模块还提供了对字符串的替换和修改函数,他们比字符串对象提供的函数功能要强大一些。这几个函数是

sub ( rule , replace , target [,count] )

subn(rule , replace , target [,count] )

在目标字符串中规格规则查找匹配的字符串,再把它们替换成指定的字符串。你可以指定一个*多替换次数,否则将替换所有的匹配到的字符串。

*个参数是正则规则,第二个参数是指定的用来替换的字符串,第三个参数是目标字符串,第四个参数是*多替换次数。

这两个函数的唯一区别是返回值。

sub返回一个被替换的字符串

sub返回一个元组,*个元素是被替换的字符串,第二个元素是一个数字,表明产生了多少次替换。

例,将下面字符串中的’dog’全部替换成’cat’

>>> s=’ I have a dog , you have a dog , he have a dog ‘

>>> re.sub( r’dog’ , ‘cat’ , s )

‘ I have a cat , you have a cat , he have a cat ‘

如果我们只想替换前面两个,则

>>> re.sub( r’dog’ , ‘cat’ , s , 2 )

‘ I have a cat , you have a cat , he have a dog ‘

或者我们想知道发生了多少次替换,则可以使用subn

>>> re.subn( r’dog’ , ‘cat’ , s )

(‘ I have a cat , you have a cat , he have a cat ‘, 3)

 

split( rule , target [,maxsplit] )

切片函数。使用指定的正则规则在目标字符串中查找匹配的字符串,用它们作为分界,把字符串切片。

*个参数是正则规则,第二个参数是目标字符串,第三个参数是*多切片次数

返回一个被切完的子字符串的列表

这个函数和str对象提供的split函数很相似。举个例子,我们想把上例中的字符串被’,’分割开,同时要去掉逗号前后的空格

>>> s=’ I have a dog   ,   you have a dog  ,  he have a dog ‘

>>> re.split( ‘/s*,/s*’ , s )

[‘ I have a dog’, ‘you have a dog’, ‘he have a dog ‘]

结果很好。如果使用str对象的split函数,则由于我们不知道’,’两边会有多少个空格,而不得不对结果再进行一次处理。

 

escape( string )

这是个功能比较古怪的函数,它的作用是将字符串中的non-alphanumerics字符(我已不知道该怎么翻译比较好了)用反义字符的形式显示出来。有时候你可能希望在正则式中匹配一个字符串,不过里面含有很多re使用的符号,你要一个一个的修改写法实在有点麻烦,你可以使用这个函数,

例 在目标字符串s中匹配’(*+?)’这个子字符串

>>> s= ‘111 222 (*+?) 333’

>>> rule= re.escape( r’(*+?)’ )

>>> print rule

/(/*/+/?/)

>>> re.findall( rule , s )

[‘(*+?)’]

3     更深入的了解re的组与对象

前面对Python正则式的组进行了一些简单的介绍,由于还没有介绍到match对象,而组又是和match对象密切相关的,所以必须将它们结合起来介绍才能充分地说明它们的用途。

不过再详细介绍它们之前,我觉得有必要先介绍一下将规则编译后的生成的patter对象

3.1编译后的Pattern对象

将一个正则式,使用compile函数编译,不仅是为了提高匹配的速度,同时还能使用一些附加的功能。编译后的结果生成一个Pattern对象,这个对象里面有很多函数,他们看起来和re模块的函数非常象,它同样有findall , match , search ,finditer , sub , subn , split 这些函数,只不过它们的参数有些小小的不同。一般说来,re模块函数的*个参数,即正则规则不再需要了,应为规则就包含在Pattern对象中了,编译选项也不再需要了,因为已经被编译过了。因此re模块中函数的这两个参数的位置,就被后面的参数取代了。

findall , match , search finditer这几个函数的参数是一样的,除了少了规则和选项两个参数外,它们又加入了另外两个参数,它们是:查找开始位置和查找结束位置,也就是说,现在你可以指定查找的区间,除去你不感兴趣的区间。它们现在的参数形式是:

findall ( targetString [, startPos [,endPos] ] )

finditer ( targetString [, startPos [,endPos] ] )

match ( targetString [, startPos [,endPos] ] )

search ( targetString [, startPos [,endPos] ] )

这些函数的使用和re模块的同名函数使用完全一样。所以就不多介绍了。

 

除了和re模块的函数同样的函数外,Pattern对象还多了些东西,它们是:

flags       查询编译时的选项

pattern 查询编译时的规则

groupindex 规则里的组

这几个不是函数,而是一个值。它们提供你一些规则的信息。比如下面这个例子

>>> p=re.compile( r'(?P<word>/b[a-z]+/b)|(?P<num>/b/d+/b)|(?P<id>/b[a-z_]+/w*/b)’ , re.I )

>>> p.flags

2

>>> p.pattern

‘(?P<word>//b[a-z]+//b)|(?P<num>//b//d+//b)|(?P<id>//b[a-z_]+//w*//b)’

>>> p.groupindex

{‘num’: 2, ‘word’: 1, ‘id’: 3}

我们来分析一下这个例子:这个正则式是匹配单词、或数字、或一个由字母或’_’开头,后面接字母或数字的一个ID。我们给这三种情况的规则都包入了一个命名组,分别命名为’word’ , ‘num’ 和 ‘id’。我们规定大小写不敏感,所以使用了编译选项 ‘I’

编译以后返回的对象为p,通过p.flag我们可以查看编译时的选项,不过它显示的不是’I’,而是一个数值。其实re.I是一个整数,2就是它的值。我们可以查看一下:

>>> re.I

2

>>> re.L

4

>>> re.M

8

每个选项都是一个数值。

通过p.pattern可以查看被编译的规则是什么。使用print的话会更好看一些

>>> print p.pattern

(?P<word>/b[a-z]+/b)|(?P<num>/b/d+/b)|(?P<id>/b[a-z_]+/w*/b)

看,和我们输入的一样。

接下来的p.groupindex则是一个字典,它包含了规则中的所有命名组。字典的key是名字,values是组的序号。由于字典是以名字作为key,所以一个无命名的组不会出现在这里。

 

 

3.2 组与Match对象

组与Match对象是Python正则式的重点。只有掌握了组和Match对象的使用,才算是真正学会了Python正则式。

3.2.1 组的名字与序号

正则式中的每个组都有一个序号,它是按定义时从左到右的顺序从1开始编号的。其实,re的正则式还有一个0号组,它就是整个正则式本身。

我们来看个例子

>>> p=re.compile( r’(?P<name>[a-z]+)/s+(?P<age>/d+)/s+(?P<tel>/d+).*’ , re.I )

>>> p.groupindex

{‘age’: 2, ‘tel’: 3, ‘name’: 1}

>>> s=’Tom 24 88888888  <=’

>>> m=p.search(s)

>>> m.groups()                           # 看看匹配的各组的情况

(‘Tom’, ’24’, ‘8888888’)

>>> m.group(‘name’)                   # 使用组名获取匹配的字符串

‘Tom’

>>> m.group( 1 )                         # 使用组序号获取匹配的字符串,同使用组名的效果一样

>>> m.group(0)                           # 0 组里面是什么呢?

‘Tom 24 88888888  <=’

原来0组就是整个正则式,包括没有被包围到组里面的内容。当获取0组的时候,你可以不写这个参数。m.group(0)m.group()的效果是一样的:

>>> m.group()

‘Tom 24 88888888  <=’

 

接下来看看更多的Match对象的方法,看看我们能做些什么。

3.2.2 Match对象的方法

group([index|id]) 获取匹配的组,缺省返回组0,也就是全部值

groups()               返回全部的组

groupdict()           返回以组名为key,匹配的内容为values的字典

接上例:

>>> m.groupindex()

{‘age’: ’24’, ‘tel’: ‘88888888’, ‘name’: ‘Tom’}

start( [group] )     获取匹配的组的开始位置

end( [group] )              获取匹配的组的结束位置

span( [group] )     获取匹配的组的(开始,结束)位置

 

expand( template ) 根据一个模版用找到的内容替换模版里的相应位置

这个功能比较有趣,它根据一个模版来用匹配到的内容替换模版中的相应位置,组成一个新的字符串返回。它使用/g<index|name> /index 来指示一个组。

接上例

>>> m.expand(r’name is /g<1> , age is /g<age> , tel is /3′)

‘name is Tom , age is 24 , tel is 88888888’

 

除了以上这些函数外,Match对象还有些属性

pos         搜索开始的位置参数

endpos  搜索结束的位置参数

这两个是使用findallmatch等函数时,传入的参数。在上面这个例子里,我们没有指定开始和结束位置,那么缺省的开始位置就是0,结束位置就是*后。

>>> m.pos

0

>>> m.endpos

19

lastindex *后匹配的组的序号

>>> m.lastindex

3

lastgroup       *后匹配的组名

>>> m.lastgroup

‘tel’

re    产生这个匹配的Pattern对象,可以认为是个逆引用

>>> m.re.pattern

‘(?P<name>[a-z]+)//s+(?P<age>//d+)//s+(?P<tel>//d+).*’

得到了产生这个匹配的规则

string 匹配的目标字符串

>>> m.string

‘Tom 24 88888888  <=’

 

 

 

更多的资料

以上基本上是把Python正则式的全面的介绍了一遍了。基本上是涵盖了Python帮助中有关正则式的全部内容。本来是想再多举点例子的,不过一来有点累了,二来觉得例子也举得够多的了,大家还是要靠自己多用多试,才能真正体会到Python 正则式的精髓。

这篇文章只能算是个学习笔记。我本身也是个初学者,错漏的地方难免,所以*可靠的,还是Python自带的帮助。以及网络上寻找的一些资料。

写这篇文章的时候我参考了以下的资料

Python正则表达式操作指南

http://wiki.ubuntu.org.cn/index.php?