月度归档: 2021 年 3 月

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

数据库服务器一般都装有数据库如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?

python下载ts视频文件

python下载ts视频文件

import requests
from multiprocessing import Pool

def mission(url,n):
headers = {“User-Agent”:”Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36″}
print(‘*****’)
response=requests.get(url,headers=headers)
print(‘—–‘)
f=open(“./1/%03d.ts”%n,”wb”)
f.write(response.content)
f.close()
print(“%03d.ts OK…”%n)

if __name__ == “__main__”:
pool=Pool(20)
for n in range(1,38):
url = “https://f1.media.brightcove.com/1/1362235890001/5796758914001/1362235890001_5796758914001_s-{}.ts?pubId=1362235890001&videoId=1655020599001”.format(n)
pool.apply_async(mission,(url,n))
pool.close()
pool.join()
在windows系统下面,直接可以使用:copy/b *.ts video.mp4  把所有ts文件合成一个mp4格式文件

华为云的下一程:与中国SaaS软件开发企业一起“乘风破浪”

%title插图%num

自三年前华为云正式发布以来,整个云计算市场发生了结构性转变:根据中国信通院《云计算白皮书(2020)》,2019年我国公有云规模首次超过了私有云规模,预计到2023年将达到2300亿元规模而届时私有云的规模将为1500亿元。换言之,未来的软件应用模式将以基于公有云的SaaS软件为主,而云计算厂商之争将从IaaS“跑马圈地”上升到争夺SaaS软件开发者生态,特别是争夺SaaS软件开发商。

《云计算白皮书(2020)》指出,2019年以互联网公司为代表的云服务商开始重视SaaS生态建设,但IaaS服务商和SaaS服务商在布局传统企业上云这一市场过程中,均存在一定短板;特别是此前IaaS 服务商虽然也有云市场等模式为SaaS服务商发展提供平台,但缺少深度合作。而作为从华为公司走出来的华为云,从一开始就非常重视与开发者生态的深度连接:2015年,华为发布沃土计划,持续投资在开放能力、平台工具、培训赋能、成果孵化、创新基金五个方面,帮助开发者获得技能、加速创新、持续发展。
%title插图%num

在2020年9月25日华为全联接大会2020第三日主题演讲中,华为云业务总裁郑叶来表示:经过三年的发展,华为云已经汇聚150万全球开发者。也就是说从2017年华为云刚发布时的近乎空白增长到3年后的150万开发者。2019年,华为推出沃土计划2.0,未来5年投资15亿美元发展云与计算开发者。在华为全联接大会2020上,华为云进一步发布了一系列的*简平台、技术使能服务和商业扶持计划,致力成为*佳应用构建平台。

郑叶来在华为全联接大会2020上特别强调,华为云期待首先成为中国软件开发企业值得信赖的伙伴。

从“三不”到“三能”
相比于2017年的华为云,今天的华为云有了什么样的重大变化?郑叶来在华为全联接大会2020上强调,这就是从“三不”到“三能”。也就是从2017年的“上不做应用,下不碰数据,不做股权投资”到今天的“赋能应用、使能数据、做智能世界的黑土地”。从“三不”到“三能”不是简单几个字的改变,郑叶来表示“而是未来三年华为云应该在产业界什么样的地位,应该为产业界贡献什么,这是一次重新思考”。
%title插图%num

从不做什么到能做什么,这在本质上体现了过去三年,华为云在技术形态上从*初的IaaS到如今具有丰富PaaS功能的结构性转变。三年前华为云正式发布,当时有三个初心:*,把华为公司在ICT领域的研发投资以云服务的形式变现;第二,把华为公司30多年积累的各种能力,通过云服务的方式提供给客户;第三,为华为公司自身,包括华为终端云服务、内部IT提供云底座,支撑全球业务发展。

过去三年,这三个初心在持续深化发展。从云服务的数量和类型来看:华为云的服务从2017年底的10大类54个,猛增到今天的210+云服务、210+解决方案;从*初的计算、存储和网络等基础IaaS公有云服务,发展到今天提供1个基于擎天架构的云基础设施底座、3个技术使能服务(应用使能、数据使能、AI使能)、4个面向行业场景化的联接触点(ROMA、DevCloud、IoT、华为云会议),已完成了从IaaS到“IaaS+PaaS”深度整合且面向政企场景的云服务。特别是去年以来陆续把ROMA、WeLink等华为数字化转型的“内功”对外输出,*大增强了华为云的软实力。

郑叶来强调,“云”在本质是软件服务,不是硬件产品,当然硬件将更好发挥软件的性能。而软件能力特别体现在3个使能服务上:AI使能服务即华为云ModelArts,应用使能服务即华为云ROMA,以及数据使能服务即华为云DAYU。值得一提的是,这三大使能服务不仅仅具备强大的软件能力,如今更进一步与行业紧密结合:华为云ModelArts提供了300+行业知识模型,应用使能服务ROMA积累了超过2000个行业应用资产,数据使能服务DAYU已上线200+行业通用数据资产模型。例如,华为云与西北空管局一起,建设了空管数据资产模型,帮助开发人员制定*佳的管制指挥方案,大幅减少了航班延误。

简而言之,今天的华为云已经成为行业数字化转型的“底座”,已经可以垂直打通和整合行业数字化转型所需的技术、数据和行业知识栈,接下来就是为行业和商业开发者提供更好的工具、平台和商业变现,让行业和商业开发者真正打开行业数字化转型的空间。

布局行业应用开发者
整个2020年,华为云与计算的一大主题就是开发者,特别是行业与商业开发者。在今年3月华为开发者大会2020(Cloud)上,华为云与计算BG总裁侯金龙就表示,IT产业本质是一个生态型产业,华为在IT产业中聚焦底层的算力、IT基础设施和云平台,而面向各个行业解决客户问题还需要很多的应用和软件,这就需要大量的开发者为各个行业、各个业务场景开发不同的软件适配。
%title插图%num

华为在去年推出了沃土计划2.0,而在今年3月的开发者大会上进一步宣布2020年将投入2亿美元。在华为全联接大会2020上,华为云进一步抛出了技术与商业变现方面的扶持。在技术工具方面,华为云为开发者提供全流程*简开发工具,通过提供1个通用工具平台和多个热点场景的工具套件,支持 Full Code和Low code/No code多种开发模式,开发效率可提升10倍。例如,利用低代码开发服务ROMA AppCube可以帮助开发者快速构建城市IOC管理中心。

在商业变现方面,华为云进一步通过两大应用分发平台,加速商业价值转化:华为云Marketplace和华为应用市场AppGallery两大应用分发平台,提供强大的应用分发能力和商业扶持计划,让开发者可以获得丰富的云资源和流量。例如,厦门卡伦特是一家成立不久的在线CAD软件提供商,2019年初开始对外提供服务,在华为云Marketplace上,短短一年销售业绩增长6倍,销售额迅速突破千万。

经过两年的发展,华为云Marketplace年交易额超过10亿元,订单数量超过10万,超过30个伙伴的销售额已经超过1000万。如今,华为云又推出了 SaaS应用扶持计划,首批扶持1000个SaaS应用,每个应用可获得*高20万元的云资源。此外,华为云联合AppGallery Connect,为集成HMS Core且上架AppGallery的创新应用提供更多技术及资源支持,推出华为云HMS生态扶持计划,首批提供5亿元的云资源,重点扶持1500个HMS应用,在商用阶段,每个应用还将获得*高120万元的广告资源扶持。

激活行业AI应用“头雁”效应
AI应用是当前所有SaaS应用和企业应用中*具活动力的应用类型,可以说在政企数字化转型中具有“头雁”效应。而行业AI开发者,主要指具备行业知识与沉淀的行业开发者,将AI应用于解决具体的行业问题。

郑叶来在华为全联接大会2020上强调,AI进入生产系统才能发挥更大价值。2018年9月全联接大会,华为云在上海发布了ModelArts,为开发者提供一站式的AI开发平台。截止华为全联接大会2020,华为云在10多个行业成功交付了600多个AI项目,ModelArts得到了广泛的应用。ModelArts在行业AI中发挥了重要价值。比如在一个铁路项目中,全车故障类型600多种,大部分故障的数据样本小于10个,数据量非常小,而基于华为云ModelArts目前已经实现重大故障的识别准确率100%,轻微故障的识别准确率98%。

华为云AI首席科学家田奇在华为全联接大会2020上介绍,华为云长期扎根AI基础技术研究,覆盖计算机视觉、语音语义和决策优化三大领域,聚焦于模型高效、数据高效、算力高效、知识高效4大方向,提出了六大基础研究计划——面向大模型的模型摸高计划、面向小模型的模型瘦身计划、面向多模态学习的数据魔方计划、面向小样本学习的数据冰山计划、面向通用知识抽取的万物预视计划和面向新学习范式的虚实合一计划。而许多研究成果,包括自动机器学习、小样本学习、联邦学习、预训练模型等,能够即插即用地部署于ModelArts使能平台,从而赋能千行百业。

%title插图%num

郑叶来在华为全联接大会2020期间发布了ModelArts 3.0,融合骨干模型、联邦学习、模型智能评估与诊断、高性能AI计算四大特性,加速行业AI落地。田奇强调,ModelArts 3.0是面向AI在行业落地提供的AI开发平台。田奇及其团队主要是从技术领域进行探索和研究,如何通过AI技术高效解决行业挑战。例如如何用*少数据训练出高精度模型、如何降低企业应用AI的门槛、如何解决企业对数据安全使用的顾虑等等。*终的结果,就是将骨干模型、联邦学习、高效算力和智能诊断评估优化等,融入了ModelArts 3.0。

所谓骨干模型,指的是基于行业小样本数据训练高精度模型,提供了AI开发的新范式。以医疗影像分割为例,过去需要成百上千例标注数据才能进行的训练,现在有了EI-Backbone,只需要几十例甚至十几例标注数据即可完成,节省标注成本90%以上。

在联邦学习方面,华为云还提供云边协同的服务,支持不同地点、不同客户的数据进行联邦训练,通过加密方式上传服务端,对全局模型进行更新,再将其下发至边缘设备,便捷支持同业态的横向联邦和跨业态的纵向联邦学习。

而为了更好地支持超大算力需求的AI研发,华为ModelArts平台在集群规模,任务数量,以及分布式训练都做了针对性的优化。例如,ModelArts平台能够管理上万的节点,更好的支持大型训练任务需求;通过优化服务框架,ModelArts平台支持10万级别的作业同时运行等等。

值得一提的是,除了骨干模型、联邦学习、高效算力和智能诊断评估优化等落地行业AI所需的关键技术外,ModerArts 3.0还在决策智能方面依托运筹优化、强化学习、智能控制等算法,构建起完整的决策底座,让AI真正实现感知-认知-决策的智能闭环,目前ModelArts驱动的决策引擎已经应用于机位分配、工业制造、智能交通、游戏娱乐等领域。

整体来说:华为云正在充分发挥过去三年所建设的“IaaS+PaaS+行业知识”所形成的“智能世界黑土地”,结合顶尖的AI研究成果并将之落地到华为云平台中,通过*简开发工具和成熟的商业变现途径,帮助广大行业和商业SaaS软件开发者,在疫情后数字化转型的新一波涨潮中“乘风破浪”,打开中国政企从数字化到数智化转型的升维空间。(文/宁川)
————————————————

原文链接:https://blog.csdn.net/achuan2015/article/details/108831906

能详细地设置 APP 权限的办法

举个例子,miui 能设置一个 APP“访问已安装的 app”的权限,但是氢 OS 就不行。
有没有办法,比如用 edxposed 或者 magisk 的模块,能够做到详细的设置一个 app 里面所有的权限?

8 条回复  •  2021-03-15 23:42:00 +08:00    
1 loli   15 天前 通用的权限用 app ops 访问已安装的 app 是 miui 魔改的,所以其他的 rom 不能用 app ops 实现 如果没有可以试试 xposed 模块 XPrivacy    
2 honeycomb   15 天前 via Android 原生 Android 的 appops 没有做这个能力,厂商自行的扩展可能会开出新功能。 此外 appops 的*大多数能力并不对外开放,那个叫“appops”的应用也是想了不少办法才能良好工作的    
3 jim9606   15 天前 需要注意 MIUI 中的“访问已安装的应用列表”、“设置媒体音量”、“读写剪贴板”都是 MIUI 自创的权限项,APP 无法感知是否授权、也无法通过 Manifest 声明是否需要这个权限,因此这几个权限所有 APP 默认都是允许的。    
4 Cielsky   15 天前 权限狗    
5 Yadomin   15 天前 安卓 11 有这个权限 `QUERY_ALL_PACKAGES`,但是没有办法控制 (    
6 benedict00   15 天前 via Android thanox    
7 ikas   14 天前 通过 AppOps 你可以控制*大部分权限,但是如果你是安卓 10 以上,这个方法目前很蛋疼,因为系统会自动修改 AppOps 状态,如果你说的控制 访问已安装的 app,你需要自己 hook 系统,或者修改系统代码实现,比如 XPrivacyLua,其可以控制 app 访问    
8 ikas   14 天前 使用 Appops 与权限来设置应用详细的权限 imgur 点 com/BG2M4DU

iPhone 检测 iPhone X 设备的几种方式和分辨率终*指南

文章目录

    • iPhone 屏幕分辨率终*指南
    • 适配新的 iPhone X 设备
    • 检测 iPhone X/XS/XR 设备的几种方式
        • 方式一:通过获取设备的 device model 来判断
        • 方式二:通过获取屏幕的宽高来判断
        • 方式三:通过底部安全区域的高度来判断
        • 方式四:通过是否支持 FaceID 判断
        • 方式五:通过 UIStatusBar 的高度判断
    • 结语
    • 原文链接
    • 参考连接本文是我们前两天发的两条小集的汇总,主要包括三部分:
      1. iPhone 屏幕分辨率总结
      2. 如何适配新的 iPhone X 设备
      3. 检测设备是否为 iPhone X/XS/XR 的几种方式

      iPhone 屏幕分辨率终*指南

      上周,苹果发布了三款新的 iPhone 设备,它们的屏幕数据分别如下:

      1. iPhone XS: 5.8 英寸,375pt * 812pt (@3x);
      2. iPhone XR: 6.1 英寸,414pt * 896pt (@2x);
      3. iPhone XS Max: 6.5 英寸,414pt * 896pt (@3x);

      在国外的 PaintCode 网站上,有一篇文章《The Ultimate Guide To iPhone Resolutions》整理了包括从*代 iPhone 到*新发布的 iPhone XS Max 等所有 iPhone 设备的屏幕数据,包括:开发尺寸(points)、物理尺寸(pixels)以及实际渲染像素、1倍/2倍/3倍模式等,如图 1 所示(建议大图查看更加清晰)。%title插图%num

    •  

      从图中数据我们可以总结以下几点:

      1. 5.8 英寸的 iPhone X/XS 与 6.1 英寸的 iPhone XR 和 6.5 英寸的 iPhone XS Max 的屏幕宽高比是一致的,约为 0.462;
      2. iPhone X/XS 的屏幕宽度(开发尺寸)与 4.7 英寸的 iPhone 8 相同,都为 375pt,只是在高度上增加了
        145pt;
      3. iPhone XR 和 iPhone XS Max 的屏幕宽度(开发尺寸)与 5.5 英寸 iPhone 8 Plus 相同,都为
        414pt,只是在高度上增加了 160pt;

      因此,设计师在出图时,仍然可以以 iPhone 8 和 iPhone 8 Plus 的屏幕宽度为基准分别进行 UI 布局,而对于不同高度的屏幕只要在纵向上进行内容延伸即可。


      适配新的 iPhone X 设备

      此外,我们发现,对于未进行新屏幕尺寸适配的工程,直接编译,在新设备 iPhone XR 和 iPhone XS Max 上运行,它们是以放大模式自动适配的(以 5.8 寸的 iPhone X 屏幕为基准等比例放大),此时在代码中获取到的屏幕宽高都为 375pt * 812pt。

      那么如何正确适配新的屏幕尺寸呢?

      1. 如果你的工程是以 LaunchScreen.storyboard 作为启动页,则只需要在 Xcode 10 下重新编译工程即可;
      2. 如果你的工程是通过配置 Assets.xcassets 里的 LaunchImage 不同尺寸的启动图片作为启动页,则你需要新增两张
        828px * 1792px 和 1242px * 2688px 分辨率的图片,如图 2 所示。
        %title插图%num

      检测 iPhone X/XS/XR 设备的几种方式

      *后,我们如何在代码中判断当前设备是否为 iPhone X 呢?

      备注:这里所说的 iPhone X 泛指上述介绍的屏幕大小为 5.8、6.1、6.5 英寸三种尺寸,且带有顶部刘海和底部操作条的 iPhone 设备。

      一开始我们采用了一种比较简便的方法:通过获取屏幕的高度,判断是否等于 812.0 或 896.0,代码如图 3 所示。
      %title插图%num

      但该方法存在小瑕疵,需要考虑一下两点:

      1. 当 App 支持横竖屏切换时,在横屏模式下也能够正确判断;
      2. 在模拟器中调试时,能够正确判断当前所选则的模拟器类型是不是 iPhone X;

      因此,我们重新整理一下目前所了解到的几种检测设备是否为 iPhone X 的方式,供大家参考,不足之处欢迎补充。

      方式一:通过获取设备的 device model 来判断

      每一台 iOS 设备都有对应的硬件编码/标识符,称为 device model 或者叫 machine name,我们可以通过如下两种方法来获取 device model/machine name。
      %title插图%num

      例如,去年发布的*代 iPhone X 对应的 device mode 为 iPhone10,3 和 iPhone10,6,而今年*新发布 iPhone XS 对应 iPhone11,2,iPhone XS Max 对应 iPhone11,4 和 iPhone11,6,iPhone XR 对应 iPhone11,8,完整的 device mode 数据参考这里:

      • https://www.theiphonewiki.com/wiki/Models

      不过需要注意的是,上述两种获取 device model 的方法在模拟器中运行得到的值为 i386 或 x86_64,因此在模拟器中我们可以通过如下方式正确获取模拟器所对应的 device model:

      // 获取模拟器所对应的 device model
      NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
      

      综上,我们可以通过判断 device model 是否为 “iPhone10,3” 和 “iPhone10,6” 或者以 “iPhone11,”(新设备)开头,来检测设备是否为 iPhone X,完整代码如下:%title插图%num

    •  

      %title插图%num方式二:通过获取屏幕的宽高来判断

      正如我们前面讲到,目前 iPhone X 设备的屏幕宽高对应的开发尺寸只有两种,分别为 375pt * 812pt 和 414pt * 896pt,因此我们可以根据屏幕的高度来判断设备是否为 iPhone X。但是此时需要考虑设备处于横屏或者竖屏的情况,这两种情况的宽高刚好是相反的(当然,如果你的 App 不用支持横屏的情况,就相对比较简单了)。

      在 UIDevice 中提供了一个 orientation 属性用于获取设备的方向(横向、竖向、或者水平),一开始我们想着先通过这个属性判断设备处于横屏或者竖屏,然后分别取其对应的屏幕宽度(横屏下)或者高度(竖屏下)来判断,但是当这个属性的值为 FaceUp 或者 FaceDown(即设备放在水平面上),我们是无法知道此时设备是处于横屏还是竖屏的。

      后面我们想了一个简便的方法,即获取屏幕的宽度和高度,取较大一方进行比较是等于 812.0 或 896.0,代码如下:
      %title插图%num

      方式三:通过底部安全区域的高度来判断

      在去年 iPhone X 发布后,为了适配顶部的浏览和底部的操作条,苹果在 iOS 11 上引入安全区域概念,建议开发者在安全区域内进行 UI 布局,因此我们可以获取屏幕 keyWindow 的 safeAreaInsets 值来判断设备是否 iPhone X。

      iPhone X 在竖屏下,keyWindow 的 safeAreaInsets 值为:

      {top: 44, left: 0, bottom: 34, right: 0}
      

      而在横屏下,其值为:

      {top: 0, left: 44, bottom: 21, right: 44}
      

      因此,我们可以比较 safeAreaInsets 的 bottom 是否等于 34.0 或者 21.0 来判断设备是否为 iPhone X,因为其他设备对应的 bottom 横竖屏下都为 0,代码如下:
      %title插图%num

      不过该方式有个不足是,必须在 AppDelegate 的 didFinishLaunchingWithOptions 回调中等 keyWindow 初始化之后才能正确判断。

      方式四:通过是否支持 FaceID 判断

      由于目前只有 iPhone X 设备支持 FaceID,因此我们也可以通过判断设备是否支持 FaceID 来判断,代码如下:%title插图%num不足:如果用户禁用 canEvaluatePolicy:error: 方法的使用将无法正确判断,而且在也不适用于模拟器中的判断。

      方式五:通过 UIStatusBar 的高度判断

      在 iPhone X 之前,所有 iPhone 设备的 StatusBar(状态栏)高度都为 20pt,而 iPhone X 的为 44pt,因此我们可以通过获取状态栏的高度判断是否等于 44.0 来检测设备是否为 iPhone X,代码如下:
      %title插图%num

      不足:该方法只适用于竖屏且显示状态栏的情况下才能正确检测,而在横屏模式下,或者 App 隐藏导航栏时,获取到的状态栏高度都为 0(statusBarFrame 的值为 CGRectZero),就无法判断了。

      你是否有其他判断方式呢?欢迎补充~


      结语

      *后,*大部分场景,我们需要检测设备是否为 iPhone X 是为了适配顶部的刘海区域和底部的操作条区域,但是这里我们更推荐通过 Auto Layout 结合 Safe Area 进行 UI 布局,以适应越来越复杂的屏幕状况。

iOS 开发之 In-App Purchase 对接教程 (一)

很久之前就想出一篇IOS内付费的教程,但是一查网上的教程实在太多了,有的写得真的蛮不错的,就心想算了,于是就保存在草稿箱了。至于为什么写完它呢!真是说来话长,*近公司有个项目经理跑来问我有关苹果内付费相关的细节,跟他聊了半天,从项目对接苹果官方支付接口聊到了如何查看App收益,*后终于使他有了一些眉目,但是悲催的是还要我继续去跟他们项目的程序员讲解(真是疯了),所以我就决定给他们项目写一个内购的文档,所以我顺便把这篇博客完成吧!

 

首先进入苹果的ItunesConnection(https://itunesconnect.apple.com)点击左上角的加号新建一个App应用,点击后该网站会弹出一个信息编辑框,大家只要将上面的信息填充完毕点击save即可在苹果的app平台上拥有一个属于自己的App。

%title插图%num

在套装ID的上,需要提前为该App申请一个AppID以及BundleID,只要是申请成功了就会在选择列表中显示出来。如果有人有疑问如何申请,请看我之前那一篇推送的博客,里面有详细的步骤。

这里顺便多说一句这个ItunesConnect是用来干嘛的,它是苹果公司给个人或企业提供管理自己App的一个平台。在这个平台上开发者可以新建,删除和管理自己的App应用,开发者可以根据需求对App应用进行上架与下架,编辑App信息,生成测试app所需的信息,例如账号,邀请码等,还有就是我们今天要讲的内付费功能。当然啦,他的功能可不止我讲的这些,我大致说一下这个平台的作用,如果你经常跟它打交道的话就会慢慢熟悉了。

 

接下来,我就来为大家演示一下如何添加付费道具,首先打开iTunesConnect,显示如下页面:

%title插图%num

选择红圈所圈起来的选项,然后将里面的相关信息补充完毕,如果缺少这一步,内购功能是不会成功的。

假如你已经完成了上述相关银行账户的设置,就点击你的App,选择上面标题栏中的”App 内购买项目”

%title插图%num

随后点击左上角的 “create new”选项,如下图所示,进入到下一个界面:

%title插图%num

 

这个界面是让你选择消费道具的种类,现在改版的网站是有简体中文翻译的,所以不像以前打开一看都不知道选哪一个,甚至都不知道每个代表的什么意思(比如我*次遇到的时候,在领导面前真是囧)。它的种类分为如下几种:

%title插图%num

 

一般对项目来说大多数都是选择“消耗型项目”这个种类,比如游戏中购买金币,宝石balabala~之类的,选中之后就会到这个界面中来:

%title插图%num

在上图所示的编辑框中输入,商品名称,产品ID以及价格等级,在这边说明一下:

1.商品名称根据你的消费道具的实际意义来说明,比如“100颗宝石”,“100金币”等。

2.产品ID是比较重要的,由项目自定义,只要唯一即可,像我一般都是用App的bundleID加一个后缀来表示,这样既跟项目关联又具有唯一性。

3.价格等级的话“查看价格表”中有对应的说明,可以对照着表中每个国家的货币价格与等级来选择。

 

我们继续,在这个网页的接下来部分如图所示:

%title插图%num

选择添加语言选项,弹出一个编辑页面:

%title插图%num

点击save保存,则会在界面上显示成如下:

%title插图%num

*后一步就是点击“选取文件”提交一张苹果它指定像素(640*920)的商品图片,当他上传完毕后点击“save”按钮,我们这第二部分就大工告成了。提交的商品*后会在内购的页面上显示为如图:

%title插图%num

这个图是我在已经发布的app上面截取的,添加了3个商品,已经是通过的的状态了(显示绿色),当您刚提交的时候,因为通过苹果的审查需要一段时间所以会显示黄色的等待状态,所以不必担心是不是商品编辑错了。如图:

%title插图%num

这部分,我主要给大家演示一下,如何申请测试账号,利用苹果的沙盒测试环境来模拟AppStore的购买流程。

在ItunesConnect中选择“用户和职能”选项~

%title插图%num

随后在左上角的选项中选择沙盒测试者,点击左上角的加号图标增加一位测试者,如图:

%title插图%num

编辑好相应的内容,点击保存,就创建了一个测试账号,是不是很简单啊!当然这个账号如果你忘记了密码可以重新生成一个,无关紧要。

顺带多句嘴,不要在正式的appstore上面用沙盒测试的账号来登录,千万要牢记在心,此账号只用于测试环境下~

 

接下来就是代码部分啦~

1.首先在项目工程中加入“storekit.framework”,加入头文件#import <StoreKit/StoreKit.h>

2.在.h文件中加入“SKPaymentTransactionObserver,SKProductsRequestDelegate”监听机制

下面贴上内购的核心代码,就几个函数,我在这边就不在做更多详细的解释了,各位看官可以运行跑一下就一目了然了。

.h文件

 

//
// PaymentViewController.h
// IAPPayTest
//
// Created by silicon on 14-10-28.
// Copyright (c) 2014年 silicon. All rights reserved.
//

#import <UIKit/UIKit.h>

#import <StoreKit/StoreKit.h>

@interface PaymentViewController : UIViewController<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@property (strong, nonatomic) IBOutlet UITextField *productID;

@property (strong, nonatomic) IBOutlet UIButton *purchase;

– (IBAction)purchaseFunc:(id)sender;

@end
.m文件

 

 

//
// PaymentViewController.m
// IAPPayTest
//
// Created by silicon on 14-10-28.
// Copyright (c) 2014年 silicon. All rights reserved.
//

#import “PaymentViewController.h”

@interface PaymentViewController ()

@end

@implementation PaymentViewController

– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

– (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
self.productID.text = @”com.games.ztyxs.product_point.1″;
}

– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

– (IBAction)purchaseFunc:(id)sender {
NSString *product = self.productID.text;
if([SKPaymentQueue canMakePayments]){
[self requestProductData:product];
}else{
NSLog(@”不允许程序内付费”);
}
}

//请求商品
– (void)requestProductData:(NSString *)type{
NSLog(@”————-请求对应的产品信息—————-“);
NSArray *product = [[NSArray alloc] initWithObjects:type, nil];

NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
[request start];

}

//收到产品返回信息
– (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{

NSLog(@”————–收到产品反馈消息———————“);
NSArray *product = response.products;
if([product count] == 0){
NSLog(@”————–没有商品——————“);
return;
}

NSLog(@”productID:%@”, response.invalidProductIdentifiers);
NSLog(@”产品付费数量:%d”,[product count]);

SKProduct *p = nil;
for (SKProduct *pro in product) {
NSLog(@”%@”, [pro description]);
NSLog(@”%@”, [pro localizedTitle]);
NSLog(@”%@”, [pro localizedDescription]);
NSLog(@”%@”, [pro price]);
NSLog(@”%@”, [pro productIdentifier]);

if([pro.productIdentifier isEqualToString:self.productID.text]){
p = pro;
}
}

SKPayment *payment = [SKPayment paymentWithProduct:p];

NSLog(@”发送购买请求”);
[[SKPaymentQueue defaultQueue] addPayment:payment];
}

//请求失败
– (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
NSLog(@”——————错误—————–:%@”, error);
}

– (void)requestDidFinish:(SKRequest *)request{
NSLog(@”————反馈信息结束—————–“);
}

//监听购买结果
– (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
for(SKPaymentTransaction *tran in transaction){

switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:
NSLog(@”交易完成”);

break;
case SKPaymentTransactionStatePurchasing:
NSLog(@”商品添加进列表”);

break;
case SKPaymentTransactionStateRestored:
NSLog(@”已经购买过商品”);

break;
case SKPaymentTransactionStateFailed:
NSLog(@”交易失败”);

break;
default:
break;
}
}
}

//交易结束
– (void)completeTransaction:(SKPaymentTransaction *)transaction{
NSLog(@”交易结束”);

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

– (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}

@end
代码就这么多,到这边我们的IOS内购教程就接近尾声了,在测试的时候还有几点因素要注意一下:

 

1.沙盒环境测试appStore内购流程的时候,请使用没越狱的设备。

2.请务必使用真机来测试,一切以真机为准。

3.项目的Bundle identifier需要与您申请AppID时填写的bundleID一致,不然会无法请求到商品信息。

讲了这么多,附上几张测试截屏给大家展示一下:

请求商品时的打印日志:

%title插图%num

交易成功后:

%title插图%num

手机截屏:

要求输入AppStore帐密,使用测试生成的即可:

%title插图%num

确定购买:

%title插图%num

交易完成:

%title插图%num

当我们的交易完成后还要去appstore 上面去验证票据信息是否正确,这样我们才可以给玩家发放道具,apple官方文档:

//交易结束
– (void)completeTransaction:(SKPaymentTransaction *)transaction{
NSLog(@”交易结束”);
//交易验证
NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];

if(!receipt){

}

NSError *error;
NSDictionary *requestContents = @{
@”receipt-data”: [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];

if (!requestData) { /* … Handle error … */ }

//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
//In the real environment, use https://buy.itunes.apple.com/verifyReceipt
// Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:@”https://buy.itunes.apple.com/verifyReceipt”];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@”POST”];
[storeRequest setHTTPBody:requestData];

// Make a connection to the iTunes Store on a background queue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
/* … Handle error … */
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) { /* … Handle error …*/ }
/* … Send a response back to the device … */
//Parse the Response
}
}];

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
好了,所有的内购流程基本上讲完了,原谅我在图片上的涂抹,因为关系到产品的敏感词汇所以希望大家能够不介意。赶这篇博客的时间比较匆忙,如果有童鞋还有什么疑问或者我写的那个地方不对欢迎私信我或者评论,我会在*时间回复。谢谢~

有无可以强制 sim 卡不漫游的小工具?

边境上,所在国的信号没有隔壁国的信号好,然后就时不时漫游到别国网络去了,这个时候电话都不能接,巨贵。

这边的卡是默认全球漫游的,自助服务里面找不到关闭的开关。运营商的服务不是用的英语。

xposed 有个 Roaming Control, *后更新是 17 年,实测无用…

还有啥神奇的小工具可以试试吗??

51 条回复  •  2021-03-16 08:53:54 +08:00

1 alfchin   15 天前 via Android   1 手动选择运营商?

2 locoz   15 天前 via Android   1 试试那些锁频工具?可以锁定使用某一个基站。

3 JensenQian   15 天前   1 两家运营商的网络频段一样吗,直接锁频段

4 JensenQian   15 天前   1 某米的机子自带这个,不过要用创建快捷方式才能弄出来

5 cathedrel   15 天前 @alfchin 选了,竟然无效,选过还是漫游,十次里面不到一次能如愿转回来,而且你试过就知道,这样操作一次基本就是在傻等…

6 cathedrel   15 天前 @locoz @JensenQian 谢谢大佬们,这样的工具给个名字?

7 JensenQian   15 天前   1 @cathedrel #6 你机子是啥 你先确定下你本地和漫游过去运营商的频段,软件可以试下,这几个 https://play.google.com/store/apps/details?id=com.qtrun.QuickTest 这个要 root 的 不 root 我找到个信通院出的,叫泰尔网测。里面有基站信号测试的,你确定下是啥频段,两边确定下 https://www.frequencycheck.com/这个网站可以查全球运营商的频段的

8 JensenQian   15 天前   1 @cathedrel #6 锁频段的话各家有各家的办法的,也不知道你手机是哪家的,具体各家怎么样的话你去酷安搜下就有

9 txydhr   15 天前 还是国内方便,运营商 app 随时打开关闭国漫

10 cathedrel   15 天前 @JensenQian 谢谢大佬。我手机硬件是米家的,rom 是 PE

11 cathedrel   15 天前   1 @txydhr 我一点都不羡慕不自由的国内,外面也不是不方便,只是人家官方服务的语言不是英语而以

12 JensenQian   15 天前   1 @cathedrel #10 r 看下这个,反正这 3 种 https://www.bilibili.com/read/cv7559527/ 小米的话 miui 可以不 root 的锁,你刷了 PE 我真的不知道怎么锁,既然都刷 PE 了应该都 root 了吧,直接用网络信号大师锁

13 JensenQian   15 天前   1 锁了频段有个缺点,就是你那边如果 4G 覆盖不好的话,可能没法接电话,记得 volte 打开

14 LOVOQ   15 天前 *简单的方法 把国漫功能整体关掉 ///

15 cathedrel   15 天前 @JensenQian 我装了 Network Signal Guru,但是打开后它并不工作,请求了 root 权限后它说”非高通基带或者驱动未启用“,这可怎么办?? 另外,frequencycheck.com 这个网站的内容比较少,我查看的这家运营商它只显示了 GSM 和 UMTS 两个频段,但实际上人家的 LTE+都上马了

16 doresu   15 天前 楼主在哪国啊啊啊

17 honeycomb   15 天前 via Android @cathedrel 这个应用只能在 qualcomm 芯片组的手机上跑

18 cathedrel   15 天前   1 @honeycomb 我这个红米手机就是高通芯片啊。我手上几个手机就没有联发科的

19 JensenQian   15 天前 @cathedrel #15 这。。。。 运营商的话你查下当地的运营商的官网吧

20 JensenQian   15 天前 @JensenQian #19 piexl 的话你试下工程模式或者直接酷安下个创建快捷方式搜 band 然后看看吧

21 484A4B   15 天前   1 自首吧

22 JensenQian   15 天前 @cathedrel #15 Network Signal Guru+小米手机刷 Pixel Experience 没法运行的我在 xda 上找到的贴子,你可以看下 https://forum.xda-developers.com/t/network-signal-guru-not-working.3898545/

23 JensenQian   15 天前   1 @JensenQian #22 https://forum.xda-developers.com/t/network-signal-guru.4005511/

24 woyaojizhu8   15 天前 我见过的所有手机设置里都有漫游开关啊,那个没用的吗

25 JensenQian   15 天前 @JensenQian #23 要么你换个软件锁,类似的软件好多了,或者刷回 miui

26 divilkcvf   15 天前 @woyaojizhu8 那个似乎仅仅针对蜂窝数据有效,语音电话是都能打通的

27 Lemeng   15 天前 什么手机,小米的试过。其他的不知道

28 Chengx3   15 天前 @woyaojizhu8 那个开关只能控制移动数据,至少我的 realme 是这样,该漫游照样会漫游,不开那个开关只是不能上网。

29 genkin   15 天前 锁定不了运营商可能是系统 bug,建议刷机换 rom

30 cathedrel   15 天前 @JensenQian 创建快捷方式我试过了,不幸的是:搜索 band 或者 roaming 都没有任何结果,看来我这个 ROM 有问题,又要折腾刷机了…

31 txydhr   15 天前 via iPhone @cathedrel 没有国漫关闭自由

32 JensenQian   15 天前   1 @cathedrel #30 那就换呗,实在不行换回 miui,eu 的 miui 试下

33 cathedrel   15 天前 @JensenQian 亲,我跟 miui 这种隐私之敌有不共戴天之仇,要换只换开源 rom,*对不会换回 miui 的

34 JensenQian   15 天前 via Android @cathedrel https://i.loli.net/2021/03/15/gYXGzv3NwSHiR4Q.jpg 这圈起来的 3 个都勾上了再搜

35 cathedrel   15 天前 @JensenQian 都勾上了,搜 band 出来一个结果,但是运行出来的界面似乎是完全无用的: i.loli.net/2021/03/15/fnEXeoWcyDbLiJz.png

36 JensenQian   15 天前 via Android @cathedrel 那估计不行了,你只能换个包,或者机换个别的软件试下吧

37 FucUrFrd   15 天前 via Android 柬埔寨 电信诈骗 罪案

38 ysc3839   15 天前 这需求不需要锁频段吧?而且锁频段也不一定可行。手机一般都有选择运营商的功能,手动选择你使用的运营商不行吗?

39 emeab   15 天前 没有国漫关闭自由

40 codingadog   15 天前 via Android 楼主是干啥的?

41 jfdnet   15 天前 不能找运营商关闭漫游功能?不关就拒付漫游费用啊。这应该很合理啊。

42 marcong95   15 天前 拿着个 Google Translate 到营业厅怎么着也能把国际漫游关掉吧,“没有自由”党连基本的国外生存技能都没么。。。

43 AirShark   15 天前 via Android @jfdnet 关了也没用,会变成网络注册失败。

44 jfdnet   15 天前 @AirShark 那网络注册失败就是信号不好呗。那你用这边推荐的办法,锁频也好什么也好,也解决不了你的问题啊。就是没信号啊。如果信号没问题注册不上,你不是一样可以找运营商么?

45 cathedrel   14 天前 @ysc3839 在我这个手机上,手动选择运营商真的没用,可能确实是 rom 有点问题 @JensenQian @jfdnet 现在解决了,昨晚临睡前在运营商官网上找了个发邮件的入口用英文发送了 roaming 功能的问题,今天醒来手机已经不漫游了,邮箱里面没有他们的回复,估计他们的英文水平写东西觉得累就没给我回复了。反正解决了问题就好 @marcong95 @emeab @txydhr 祝你们生生世世享受国漫关闭自由

46 marcong95   14 天前 @cathedrel #45 我对国际漫游关闭自由没有需求,只是想好奇你们张口自由闭口隐私的连国外生活的基本技能(例如本地语言、翻译软件等)都没有的吗?个人而言只是不太爽你们(包括但不限于你、以及你把我 @在一起的那些国际漫游关闭自由的)什么奇奇怪怪的东西都能往政治上靠。

47 emeab   14 天前 15 天前 还在找$$配置 今天就一键转生国外自由人了?

48 cathedrel   14 天前 @emeab 在中国之外你就不要保护隐私了? @marcong95 你理解“懒”这个字吗?如果可以在家里敲敲键盘或者打打电话就能解决问题的话,为什么还要跑出门呢?

49 spacezip   14 天前 高通 root cellular pro 锁网 锁频段 锁小区 锁频点。。。。

50 txydhr   14 天前 via iPhone @emeab @marcong95 他自己先把话题带跑偏的。估计楼主是搞了张对面国手机卡,不想漫游到国内运营商。

51 jfdnet   14 天前 @cathedrel @emeab $$或者类似的技术之所以被称为透明代理,也就意味着它(它们)提供不了隐私保护的能力。楼主要是有这方面的需求,可得小心。

PHPWAMP配置应该如何修改,Web服务器、php、mysql的具体配置修改

phpwamp支持Nginx、apache、iis(均为完整版更稳定)

默认集成了多个php版本,包含TS与NTS,(支持自定义php版本)

Mysql默认集成了mysql5.5、mysql5.6、mysql7(支持自定义Mysql版本)

今天我们来详细讲解PHPWAMP的配置修改方式

1、修改Apache、Nginx服务器的配置,如下图,可以点击相关设置,修改服务器配置

(友情提示,nginx、apache、iis的配置也可以在站点管理里面的右键菜单修改)

%title插图%num

2、PHPWAMP主界面切换的php版本是默认站点的版本,修改默认站点的PHP配置可点击相关设置,修改PHP配置站点管理里面的php版本并非是修改此处,站点管理的php配置请在站点管理里面修改(默认集成的PHP包含ts与nts)

(注意:主界面的php版本和站点管理里面的并不相同,主界面默认站点的6个php版本是安全线程的,并且采用的是模块运行方式,而站点管理里面的php版本采用的是非安全线程,属于FCGI运行模式)

%title插图%num

3、*方便的当然是直接右键站点管理修改配置了,右键点击站点可以修改对应的php与Web服务器的配置

(注意:站点管理里面的php5.2、php5.3、php5.4、php5.5、php5.6、php7采用的是FCGI运行模式,并且是NTS。如果在站点管理里面选择默认php版本,那么就是选择了主界面当前默认的php版本,是模块运行方式、TS的php版本。)

%title插图%num

4、修改Mysql数据库配置,点击相关设置,点击修改数据库配置即可,

(此处修改的是当前的mysql数据库配置,想修改其他Mysql版本的数据库配置,请先切换到其他mysql版本)

%title插图%num

5、点击菜单栏的编辑文件,可以找到php、Web服务器、mysql数据库的物理文件所在的位置。

%title插图%num

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速