• [交流吐槽] 隐式的类类型转换(转换构造函数)
    如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数又叫转换构造函数(converting constructor)。能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则。只允许 一步类类型转换抑制构造函数定义的隐式转换将构造函数声明为 explicit加以阻止explicit关键字只允许出现在类内的构造函数声明处(只对一个实参的构造函数有效)explicit构造函数只能用于直接初始化,不能将explicit构造函数用于拷贝形式的初始化过程。Sales_data item1(null_book);   //正确,直接初始化Sales_data item2 = null_book;  //错误:不能将 explicit 构造函数用于拷贝形式的初始化过程尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们可以使用这样的构造函数 显式地强制进行转换。
  • [其他] 基于OpenCV的条形码区域分割
    分割是识别图像内一个或多个对象的位置的过程。我们要介绍的技术其实非常简单,它利用了形态算子的扩张和侵蚀,以及诸如开运算,闭运算和黑帽算子的组合。01.简介安装Anaconda后,让我们从Anaconda的提示符下使用以下命令转到OpenCV安装:conda install -c https://conda.anaconda.org/menpo opencv现在,让我们从Anaconda启动器启动Spyder IDE。Anaconda启动器一旦运行了Spyder,建议验证OpenCV安装是否成功。在Python控制台的右下角,我们进行以下测试:import cv2代码讲解我们已经创建了一个启动GitHub存储库。小伙伴可以使用以下方法直接克隆它:git clone --branch step1 https://github.com/lucapiccinelli/BarcodesTutorial.git现在,我们将要下载测试图像,并对他们进行读取和显示。import cv2 import matplotlib.pyplot as plt im = cv2.imread(r’img\barcodes.jpg’, cv2.IMREAD_GRAYSCALE) plt.imshow(im, cmap=’Greys_r’)接下来,我们将对图像进行二值化处理,这样可以通过阈值的设定来提取出我们感兴趣的部分。使用黑帽运算符,我们可以增加较暗的图像元素。我们可以首先使用简单的全局阈值安全地对图像进行二值化处理。黑帽运算符使我们可以使用非常低的阈值,而不必过多地关注噪声。在应用blackhat时,我们使用的内核会更加重视垂直图像元素。内核具有固定的大小,因此可以缩放图像,这也可以提高性能(并支持某种输入归一化)。黑帽+阈值处理它遵循其他形态运算符的采用,顺序地将它们组合在一起以获得条形码位置中的连接组件。#riscalatura dell'immagine scale = 800.0 / im.shape[1] im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale))) #blackhat kernel = np.ones((1, 3), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel, anchor=(1, 0)) #sogliatura thresh, im = cv2.threshold(im, 10, 255, cv2.THRESH_BINARY)膨胀和闭合的这种组合在测试图像上效果很好,但可能无法在其他图像上达到相同的效果。这没有关系,大家可以尝试改变参数和运算符的组合,直到对结果满意为止。膨胀+闭运算最后的预处理步骤是应用具有很大内核的开运算符,以删除太少而无法适合条形码形状的元素。kernel = np.ones((21, 35), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)这是我们希望得到的最终结果:使用35x21内核打开现在,我们可以运行连接的组件的检测算法,并检索带有坐标和尺寸的条形码矩形。如大家在上一张图像中所看到的那样,最后的形态学步骤并未滤除全部的噪声。但是,在这种情况下,将它们过滤掉非常简单,以矩形区域值作为阈值就可以了。#rilettura dell'immagine, stavolta a colori im_out = cv2.imread(r'img\barcodes.jpg') #estrazione dei componenti connessi contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) unscale = 1.0 / scale if contours != None: for contour in contours: # se l'area non è grande a sufficienza la salto if cv2.contourArea(contour) <= 2000: continue #estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo) rect = cv2.minAreaRect(contour) #l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate rect = \ ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \ (int(rect[1][0] * unscale), int(rect[1][1] * unscale)), \ rect[2]) #disegno il tutto sull'immagine originale box = np.int0(cv2.cv.BoxPoints(rect)) cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness = 2) plt.imshow(im_out) #scrittura dell' immagine finale cv2.imwrite(r'img\out.png', im_out)最后,在上面的代码中,我使用提取的矩形绘制它们,并将其覆盖在原始图像上。最终结果,条形码以绿色框突出显示。结论• 提出的技术非常简单有效,但存在一些令人讨厌的缺点:• 它对条形码偏斜非常敏感;它可以很好地工作到大约45度,然后您必须执行第二遍,修改内核的方向。• 它只能在固定尺寸范围内找到条形码。• 尽管对矩形区域施加了过滤,但仍有可能无法清除某些非条形码。第一个和第二个可能不是真正的问题,但是最后一个可能会花费大家大量时间来尝试解码非条形码的内容。一个很好的解决方案是将条形码特征(图像梯度,傅立叶变换)输入给神经网络(或一些其他一些分类器),并在第二时刻过滤掉噪声。
  • [技术干货] Xpath语法格式总结
    经常在工作中会使用到XPath的相关知识,但每次总会在一些关键的地方不记得或不太清楚,所以免不了每次总要查一些零碎的知识,感觉即很烦又浪费时间,所以对XPath归纳及总结一下。在这篇文章中你将能学习到:XPath简介XPath 路径表达式详解XPath在DOM,XSLT及XQuery中的应用XPath简介XPath是W3C的一个标准。它最主要的目的是为了在XML1.0或XML1.1文档节点树中定位节点所设计。目前有XPath1.0和XPath2.0两个版本。其中Xpath1.0是1999年成为W3C标准,而XPath2.0标准的确立是在2007年。W3C关于XPath的英文详细文档请见:http://www.w3.org/TR/xpath20/ 。XPath是一种表达式语言,它的返回值可能是节点,节点集合,原子值,以及节点和原子值的混合等。XPath2.0是XPath1.0的超集。它是对XPath1.0的扩展,它可以支持更加丰富的数据类型,并且XPath2.0保持了对XPath1.0的相对很好的向后兼容性,几乎所有的XPath2.0的返回结果都可以和XPath1.0保持一样。另外XPath2.0也是XSLT2.0和XQuery1.0的用于查询定位节点的主表达式语言。XQuery1.0是对XPath2.0的扩展。关于在XSLT和XQuery中使用XPath表达式定位节点的知识在后面的实例中会有所介绍。在学习XPath之前你应该对XML的节点,元素,属性,原子值(文本),处理指令,注释,根节点(文档节点),命名空间以及对节点间的关系如:父(Parent),子(Children),兄弟(Sibling),先辈(Ancestor),后代(Descendant)等概念有所了解。这里不在说明。XPath路径表达式在本小节下面的内容中你将可以学习到:路径表达式语法相对/绝对路径表达式上下文谓词(筛选表达式)及轴的概念运算符及特殊字符常用表达式实例函数及说明这里给出一个实例Xml文件。下面的说明及实例都是基于该XML文件。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465<?xml version="1.0" encoding="UTF-8"?><!-- edited with XMLSpy v2008 rel. 2 sp2 (http://www.altova.com ) by Administrator --><?xml-stylesheet type="text/xsl" href="messages.xsl" rel="external nofollow" ?><messages> <message id="1"> <sender>gukaitong@gmail.com</sender> <to>anonymous@gmail.com <group name="IT"> <address>111@gmail.com</address> <address>222@gmail.com</address> <address>aaa@gmail.com</address> <address>bbb@gmail.com</address> <address>ccc@gmail.com</address> </group> </to> <subject>This is a sample</subject> <datetime date="2008-12-11" time="12:00:00" formatted="12/11/2008 12:00AM">2008-12-11T12:00:00Z</datetime> <body> Are you interested in?  <attachments> <attachment id="1">  <message id="0">  <sender>anonymous@gmail.com</sender>  <to>gukaitong@gmail.com</to>  <body>We strongly recommend the following books  <books xmlns:amazon="http://www.amazon.com/books/schema ">  <amazon:book>   <name>Professional C# 2008 </name>   <country>USA</country>   <price>37.79</price>   <year>2007</year>  </amazon:book>  <amazon:book>   <name>Microsoft Visual C# 2008 Step by Step </name>   <country>USA</country>   <price>26.39 </price>   <year>2008</year>  </amazon:book>  <amazon:book>   <name>C# in Depth</name>   <country>USA</country>   <price>29.69 </price>   <year>2006</year>  </amazon:book>  <amazon:book>   <name>Thinking in Java</name>   <country>USA</country>   <price>23.69 </price>   <year>2004</year>  </amazon:book>  </books>  </body>  </message> </attachment> </attachments> </body> </message> <message id="2"> <sender>333@gmail.com</sender> <to>444@gmail.com</to> <subject>No title</subject> <body/> </message></messages>路径表达式语法:路径 = 相对路径 | 绝对路径XPath路径表达式 = 步进表达式 | 相对路径 "/"步进表达式。步进表达式=轴 节点测试 谓词说明:其中轴表示步进表达式选择的节点和当前上下文节点间的树状关系(层次关系),节点测试指定步进表达式选择的节点名称扩展名,谓词即相当于过滤表达式以进一步过滤细化节点集。谓词可以是0个或多个。多个多个谓词用逻辑操作符and, or连接。取逻辑非用not()函数。请看一个典型的XPath查询表达式:/messages/message//child::node()[@id=0],其中/messages/message是路径(绝对路径以"/"开始),child::是轴表示在子节点下选择,node()是节点测试表示选择所有的节点。[@id=0]是谓词,表示选择所有有属性id并且值为0的节点。相对路径与绝对路径:如果"/"处在XPath表达式开头则表示文档根元素,(表达式中间作为分隔符用以分割每一个步进表达式)如:/messages/message/subject是一种绝对路径表示法,它表明是从文档根开始查找节点。假设当前节点是在第一个message节点【/messages/message[1]】,则路径表达式subject(路径前没有"/")这种表示法称为相对路径,表明从当前节点开始查找。具体请见下面所述的"表达式上下文"。表达式上下文(Context):上下文其实表示一种环境。以明确当前XPath路径表达式处在什么样的环境下执行。例如同样一个路径表达式处在对根节点操作的环境和处在对某一个特定子节点操作的环境下执行所获得的结果可能是完全不一样的。也就是说XPath路径表达式计算结果取决于它所处的上下文。XPath上下文基本有以下几种:当前节点(./):如./sender表示选择当前节点下的sender节点集合(等同于下面所讲的"特定元素",如:sender)父节点(../):如../sender表示选择当前节点的父节点下的sender节点集合根元素(/):如/messages表示选择从文档根节点下的messages节点集合.根节点(/*):这里的*是代表所有节点,但是根元素只有一个,所以这里表示根节点。/*的返回结果和/messages返回的结果一样都是messages节点。递归下降(//):如当前上下文是messages节点。则//sender将返回以下结果:/messages//sender :<sender>gkt1980@gmail.com</sender><sender>111@gmail.com</sender><sender>333@gmail.com</sender>/messages/message[1]//sender:<sender>gkt1980@gmail.com</sender><sender>111@gmail.com</sender>我们可以看出XPath表达式返回的结果是:从当前节点开始递归步进搜索当前节点下的所有子节点找到满足条件的节点集。特定元素如sender:表示选择当前节点下的sender节点集合,等同于(./sender)注意:在执行XPath时一定要注意上下文。即当前是在哪个节点下执行XPath表达式。这在XMLDOM中很重要。如:在XMLDOM中的selectNodes,selectSingleNode方法的参数都是一个XPath表达式,此时这个XPath表达式的执行上下文就是调用这个方法的节点及它所在的环境。更多信息请参见:http://www.w3.org/TR/xpath20/谓词(筛选表达式)及轴的概念:XPath的谓词即筛选表达式,类似于SQL的where子句.轴名称结果ancestor选取当前节点的所有先辈(父、祖父等)ancestor-or-self选取当前节点的所有先辈(父、祖父等)以及当前节点本身attribute选取当前节点的所有属性child选取当前节点的所有子元素。descendant选取当前节点的所有后代元素(子、孙等)。descendant-or-self选取当前节点的所有后代元素(子、孙等)以及当前节点本身。following选取文档中当前节点的结束标签之后的所有节点。namespace选取当前节点的所有命名空间节点parent选取当前节点的父节点。preceding直到所有这个节点的父辈节点,顺序选择每个父辈节点前的所有同级节点preceding-sibling选取当前节点之前的所有同级节点。self选取当前节点。运算符及特殊字符:运算符/特殊字符说明/此路径运算符出现在模式开头时,表示应从根节点选择。//从当前节点开始递归下降,此路径运算符出现在模式开头时,表示应从根节点递归下降。.当前上下文。..当前上下文节点父级。*通配符;选择所有元素节点与元素名无关。(不包括文本,注释,指令等节点,如果也要包含这些节点请用node()函数)@属性名的前缀。@*选择所有属性,与名称无关。:命名空间分隔符;将命名空间前缀与元素名或属性名分隔。( )括号运算符(优先级最高),强制运算优先级。[ ]应用筛选模式(即谓词,包括"过滤表达式"和"轴(向前/向后)")。[ ]下标运算符;用于在集合中编制索引。|两个节点集合的联合,如://messages/message/to | //messages/message/cc-减法。div,浮点除法。and, or逻辑运算。mod求余。not()逻辑非=等于!=不等于特殊比较运算符< 或者 &lt;<= 或者 &lt;=> 或者 &gt;>= 或者 &gt;=需要转义的时候必须使用转义的形式,如在XSLT中,而在XMLDOM的scripting中不需要转义。常用表达式实例:/Document Root文档根./*选择文档根下面的所有元素节点,即根节点(XML文档只有一个根节点)/node()根元素下所有的节点(包括文本节点,注释节点等)/text()查找文档根节点下的所有文本节点/messages/messagemessages节点下的所有message节点/messages/message[1]messages节点下的第一个message节点/messages/message[1]/self::node()第一个message节点(self轴表示自身,node()表示选择所有节点)/messages/message[1]/node()第一个message节点下的所有子节点/messages/message[1]/*[last()]第一个message节点的最后一个子节点/messages/message[1]/[last()]Error,谓词前必须是节点或节点集/messages/message[1]/node()[last()]第一个message节点的最后一个子节点/messages/message[1]/text()第一个message节点的所有子节点/messages/message[1]//text()第一个message节点下递归下降查找所有的文本节点(无限深度)/messages/message[1] /child::node()/messages/message[1] /node()/messages/message[position()=1]/node()//message[@id=1] /node()第一个message节点下的所有子节点//message[@id=1] //child::node()递归所有子节点(无限深度)//message[position()=1]/node()选择id=1的message节点以及id=0的message节点/messages/message[1] /parent::*Messages节点/messages/message[1]/body/attachments/parent::node()/messages/message[1]/body/attachments/parent::* /messages/message[1]/body/attachments/..attachments节点的父节点。父节点只有一个,所以node()和* 返回结果一样。(..也表示父节点. 表示自身节点)//message[@id=0]/ancestor::*Ancestor轴表示所有的祖辈,父,祖父等。向上递归//message[@id=0]/ancestor-or-self::*向上递归,包含自身//message[@id=0]/ancestor::node()对比使用*,多一个文档根元素(Document root)/messages/message[1]/descendant::node()//messages/message[1]//node()递归下降查找message节点的所有节点/messages/message[1]/sender/following::*查找第一个message节点的sender节点后的所有同级节点,并对每一个同级节点递归向下查找。//message[@id=1]/sender/following-sibling::*查找id=1的message节点的sender节点的所有后续的同级节点。//message[@id=1]/datetime/@date查找id=1的message节点的datetime节点的date属性//message[@id=1]/datetime[@date]//message/datetime[attribute::date]查找id=1的message节点的所有含有date属性的datetime节点//message[datetime]查找所有含有datetime节点的message节点//message/datetime/attribute::*//message/datetime/attribute::node()//message/datetime/@*返回message节点下datetime节点的所有属性节点//message/datetime[attribute::*]//message/datetime[attribute::node()]//message/datetime[@*]//message/datetime[@node()]选择所有含有属性的datetime节点//attribute::*选择根节点下的所有属性节点//message[@id=0]/body/preceding::node()顺序选择body节点所在节点前的所有同级节点。(查找顺序为:先找到body节点的顶级节点(根节点),得到根节点标签前的所有同级节点,执行完成后继续向下一级,顺序得到该节点标签前的所有同级节点,依次类推。)注意:查找同级节点是顺序查找,而不是递归查找。//message[@id=0]/body/preceding-sibling::node()顺序查找body标签前的所有同级节点。(和上例一个最大的区别是:不从最顶层开始到body节点逐层查找。我们可以理解成少了一个循环,而只查找当前节点前的同级节点)//message[@id=1]//*[namespace::amazon]查找id=1的所有message节点下的所有命名空间为amazon的节点。//namespace::*文档中的所有的命名空间节点。(包括默认命名空间xmlns:xml)//message[@id=0]//books/*[local-name()='book']选择books下的所有的book节点,注意:由于book节点定义了命名空间<amazone:book>.若写成//message[@id=0]//books/book则查找不出任何节点。//message[@id=0]//books/*[local-name()='book' and namespace-uri()='http://www.amazon.com/books/schema']选择books下的所有的book节点,(节点名和命名空间都匹配)//message[@id=0]//books/*[local-name()='book'][year>2006]选择year节点值>2006的book节点//message[@id=0]//books/*[local-name()='book'][1]/year>2006指示第一个book节点的year节点值是否大于2006.返回xs:boolean: true函数及说明:值得欣喜的是XPath函数和XSLT,XQuery等共享函数库,函数库为我们提供了功能丰富的各种函数的调用,我们也可以自定义自己的函数。这里不再对每个函数的用法逐一说明,中文的可以参考这个网站, https://www.jb51.net/w3school/xpath/index.htm XPath在DOM,XSLT及XQuery中的应用DOM:123456789101112131415161718192021<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd "><html xmlns="http://www.w3.org/1999/xhtml "><head><title>XPath Test</title></head><body><script language="javascript" type="text/javascript">var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async="false";xmlDoc.load("messages.xml");xmlDoc.setProperty("SelectionLanguage", "XPath"); var sPath = "/messages/message[1]//books/*[local-name()='book']";var bookNodes = xmlDoc.selectNodes(sPath);document.write("<ul>");for ( var i = 0; i < bookNodes.length; i++) {document.write("<li>" + bookNodes[i].childNodes[0].text + "</li>");}document.write("</ul>");</script></body></html>注意:我们若使用new ActiveXObject("Microsoft.XMLDOM")则需要注意的是:因为早期的XMLDOM的SelectionLanguage属性默认是正则表达式,不是XPath语言。所以需要指定这样一条语句xmlDoc.setProperty("SelectionLanguage", "XPath"); 以支持XPath查询表达式。.若没有指定SelectionLanguage属性值为XPath则要注意以下情况:数组下标从0开始(我们知道在XPath查询表达式中数组下标是从1开始的)不支持在XPath查询表达式中使用XPath函数。总结以上就是本文关于Xpath语法格式总结的全部内容,希望对大家有所帮助
  • [技术干货] shell-基本运算符 下
    实例字符串运算符实例如下:实例#!/bin/bash# author:华为教程# url:www.huawei.coma="abc"b="efg"if [ $a = $b ]then   echo "$a = $b : a 等于 b"else   echo "$a = $b: a 不等于 b"fiif [ $a != $b ]then   echo "$a != $b : a 不等于 b"else   echo "$a != $b: a 等于 b"fiif [ -z $a ]then   echo "-z $a : 字符串长度为 0"else   echo "-z $a : 字符串长度不为 0"fiif [ -n "$a" ]then   echo "-n $a : 字符串长度不为 0"else   echo "-n $a : 字符串长度为 0"fiif [ $a ]then   echo "$a : 字符串不为空"else   echo "$a : 字符串为空"fi执行脚本,输出结果如下所示:abc = efg: a 不等于 babc != efg : a 不等于 b-z abc : 字符串长度不为 0-n abc : 字符串长度不为 0abc : 字符串不为空文件测试运算符文件测试运算符用于检测 Unix 文件的各种属性。属性检测描述如下:其他检查符:-S: 判断某文件是否 socket。-L: 检测文件是否存在并且是一个符号链接。实例变量 file 表示文件 /var/www/huawei/test.sh,它的大小为 100 字节,具有 rwx 权限。下面的代码,将检测该文件的各种属性:实例#!/bin/bash# author:华为教程# url:www.huawei.comfile="/var/www/huawei/test.sh"if [ -r $file ]then   echo "文件可读"else   echo "文件不可读"fiif [ -w $file ]then   echo "文件可写"else   echo "文件不可写"fiif [ -x $file ]then   echo "文件可执行"else   echo "文件不可执行"fiif [ -f $file ]then   echo "文件为普通文件"else   echo "文件为特殊文件"fiif [ -d $file ]then   echo "文件是个目录"else   echo "文件不是个目录"fiif [ -s $file ]then   echo "文件不为空"else   echo "文件为空"fiif [ -e $file ]then   echo "文件存在"else   echo "文件不存在"fi执行脚本,输出结果如下所示:文件可读文件可写文件可执行文件为普通文件文件不是个目录文件不为空文件存在
  • [技术干货] shell-基本运算符 中
    实例布尔运算符实例如下:实例#!/bin/bash# author:华为教程# url:www.huawei.coma=10b=20if [ $a != $b ]then   echo "$a != $b : a 不等于 b"else   echo "$a == $b: a 等于 b"fiif [ $a -lt 100 -a $b -gt 15 ]then   echo "$a 小于 100 且 $b 大于 15 : 返回 true"else   echo "$a 小于 100 且 $b 大于 15 : 返回 false"fiif [ $a -lt 100 -o $b -gt 100 ]then   echo "$a 小于 100 或 $b 大于 100 : 返回 true"else   echo "$a 小于 100 或 $b 大于 100 : 返回 false"fiif [ $a -lt 5 -o $b -gt 100 ]then   echo "$a 小于 5 或 $b 大于 100 : 返回 true"else   echo "$a 小于 5 或 $b 大于 100 : 返回 false"fi执行脚本,输出结果如下所示:10 != 20 : a 不等于 b10 小于 100 且 20 大于 15 : 返回 true10 小于 100 或 20 大于 100 : 返回 true10 小于 5 或 20 大于 100 : 返回 false逻辑运算符以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:实例逻辑运算符实例如下:实例#!/bin/bash# author:华为教程# url:www.huawei.coma=10b=20if [[ $a -lt 100 && $b -gt 100 ]]then   echo "返回 true"else   echo "返回 false"fiif [[ $a -lt 100 || $b -gt 100 ]]then   echo "返回 true"else   echo "返回 false"fi执行脚本,输出结果如下所示:返回 false返回 true字符串运算符下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
  • [技术干货] shell-基本运算符 上
    Shell 和其他编程语言一样,支持多种运算符,包括:算数运算符关系运算符布尔运算符字符串运算符文件测试运算符原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。expr 是一款表达式计算工具,使用它能完成表达式的求值操作。例如,两个数相加(注意使用的是反引号 ` 而不是单引号 '):实例#!/bin/bashval=`expr 2 + 2`echo "两数之和为 : $val"运行实例 »执行脚本,输出结果如下所示:两数之和为 : 4两点注意:表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。实例算术运算符实例如下:实例#!/bin/bash# author:华为教程# url:www.hauwei.coma=10b=20val=`expr $a + $b`echo "a + b : $val"val=`expr $a - $b`echo "a - b : $val"val=`expr $a \* $b`echo "a * b : $val"val=`expr $b / $a`echo "b / a : $val"val=`expr $b % $a`echo "b % a : $val"if [ $a == $b ]then   echo "a 等于 b"fiif [ $a != $b ]then   echo "a 不等于 b"fi执行脚本,输出结果如下所示:a + b : 30a - b : -10a * b : 200b / a : 2b % a : 0a 不等于 b注意:乘号(*)前边必须加反斜杠(\)才能实现乘法运算;if...then...fi 是条件语句,后续将会讲解。在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\" 。实例关系运算符实例如下:实例#!/bin/bash# author:华为教程# url:www.huawei.coma=10b=20if [ $a -eq $b ]then   echo "$a -eq $b : a 等于 b"else   echo "$a -eq $b: a 不等于 b"fiif [ $a -ne $b ]then   echo "$a -ne $b: a 不等于 b"else   echo "$a -ne $b : a 等于 b"fiif [ $a -gt $b ]then   echo "$a -gt $b: a 大于 b"else   echo "$a -gt $b: a 不大于 b"fiif [ $a -lt $b ]then   echo "$a -lt $b: a 小于 b"else   echo "$a -lt $b: a 不小于 b"fiif [ $a -ge $b ]then   echo "$a -ge $b: a 大于或等于 b"else   echo "$a -ge $b: a 小于 b"fiif [ $a -le $b ]then   echo "$a -le $b: a 小于或等于 b"else   echo "$a -le $b: a 大于 b"fi执行脚本,输出结果如下所示:10 -eq 20: a 不等于 b10 -ne 20: a 不等于 b10 -gt 20: a 不大于 b10 -lt 20: a 小于 b10 -ge 20: a 小于 b10 -le 20: a 小于或等于 b
  • [技术干货] php字符串变量
    PHP 中的字符串变量字符串变量用于包含有字符的值。在创建字符串之后,我们就可以对它进行操作了。您可以直接在函数中使用字符串,或者把它存储在变量中。在下面的实例中,我们创建一个名为 txt 的字符串变量,并赋值为 "Hello world!" 。然后我们输出 txt 变量的值:实例<?php$txt="Hello world!";echo $txt;?>lamp    注释:当您赋一个文本值给变量时,请记得给文本值加上单引号或者双引号。现在,让我们来看看一些常用的操作字符串的函数和运算符。PHP 并置运算符在 PHP 中,只有一个字符串运算符。并置运算符 (.) 用于把两个字符串值连接起来。下面的实例演示了如何将两个字符串变量连接在一起:实例<?php$txt1="Hello world!";$txt2="What a nice day!";echo $txt1 . " " . $txt2;?>上面的代码将输出:Hello world! What a nice day!提示:在上面的代码中,我们已经使用了两次并置运算符。这是由于我们需要在两个字符串之间插入一个空格。PHP strlen() 函数有时知道字符串值的长度是很有用的。strlen() 函数返回字符串的长度(字节数)。下面的实例返回字符串 "Hello world!" 的长度:实例<?phpecho strlen("Hello world!");?>上面的代码将输出:12提示:strlen() 常常用在循环和其他函数中,因为那时确定字符串何时结束是很重要的。(例如,在循环中,我们需要在字符串中的最后一个字符之后结束循环。)PHP strpos() 函数strpos() 函数用于在字符串内查找一个字符或一段指定的文本。如果在字符串中找到匹配,该函数会返回第一个匹配的字符位置。如果未找到匹配,则返回 FALSE。下面的实例在字符串 "Hello world!" 中查找文本 "world":实例<?phpecho strpos("Hello world!","world");?>上面的代码将输出:6提示:在上面的实例中,字符串 "world" 的位置是 6。之所以是 6 而不是 7 的原因是,字符串中第一个字符的位置是 0,而不是 1。
  • [交流吐槽] 隐式的类类型转换(转换构造函数)
    如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数又叫转换构造函数(converting constructor)。能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则。只允许 一步类类型转换抑制构造函数定义的隐式转换将构造函数声明为 explicit加以阻止explicit关键字只允许出现在类内的构造函数声明处(只对一个实参的构造函数有效)explicit构造函数只能用于直接初始化,不能将explicit构造函数用于拷贝形式的初始化过程。Sales_data item1(null_book);   //正确,直接初始化Sales_data item2 = null_book;  //错误:不能将 explicit 构造函数用于拷贝形式的初始化过程尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们可以使用这样的构造函数 显式地强制进行转换。
  • [交流吐槽] 面向对象和面向过程的区别
    面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发面向对象:是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要低。
  • [技术干货] PromQL简介
    PromQL(Prometheus Query Language) 是 Prometheus 自己开发的数据查询 DSL 语言,语言表现力非常丰富,支持条件查询、操作符,并且内建了大量内置函数,供我们针对监控数据的各种维度进行查询。监控数据结构毕竟有限,相比于SQL语言,语法更简单直接。查询数据方式分为瞬时向量查询和范围向量查询:目标实例状态:up查询指标最新样本(称为瞬时向量):例如node_cpu_seconds_total可以通过附加一组标签来进一步过来这些时间序列:node_cpu_seconds_total{job="Linux Server"}查询指标近5分钟内样本(称为范围向量,时间单位 s,m,h,d,w,y):node_cpu_seconds_total{job="Linux Server"}[5m]node_cpu_seconds_total{job="Linux Server"}[1h]支持的数据操作类型:比较操作符:= 等于!= 不等于 > 大于 < 小于 >= 大于等于 <= 小于等于示例:node_cpu_seconds_total{job="Linux Server",mode="iowait"}            node_cpu_seconds_total{job="Linux Server",mode=~"user|system",cpu!="0"}算术操作符 + 加法 - 减法 * 乘法 / 除法内存使用率:100 - (node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) /node_memory_MemTotal_bytes * 100正则匹配操作符 =~ 正则表达式匹配!~ 正则表达式匹配结果取反磁盘使用率:100-(node_filesystem_free_bytes{mountpoint="/",fstype=~"ext4|xfs"}/node_filesystem_size_bytes{mountpoint="/",fstype=~"ext4|xfs"} * 100)聚合操作符sum (在维度上求和)max (在维度上求最大值)min (在维度上求最小值)avg (在维度上求平均值)count(统计样本数量)所有实例CPU system使用率总和:sum(node_cpu_seconds_total{job="Linux Server",mode="system"}) 逻辑操作符 and 与or 或大于10并且小于50:prometheus_http_requests_total > 10 and prometheus_http_requests_total < 50
  • [技术干货] like - 技巧与建议
    MySQL的通配符很有用。但这种功能是有代价的:通配符搜索的处理一般要比前面讨论的其他搜索所花时间更长。这里给出一些使用通配符要记住的技巧。不要过度使用通配符。如果其他操作符能达到相同的目的,应该 使用其他操作符。在确实需要使用通配符时,除非绝对有必要,否则不要把它们用 在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起 来是最慢的。仔细注意通配符的位置。如果放错地方,可能不会返回想要的数.
  • [技术干货] like %和-的区别
    通配符的分类:%百分号通配符:表示任何字符出现任意次数(可以是0次)._下划线通配符:表示只能匹配单个字符,不能多也不能少,就是一个字符.like操作符: LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配进行比较.注意: 如果在使用like操作符时,后面的没有使用通用匹配符效果是和=一致的,SELECT * FROM products WHERE products.prod_name like '1000';只能匹配的结果为1000,而不能匹配像JetPack 1000这样的结果.%通配符使用: 匹配以"yves"开头的记录:(包括记录"yves") SELECT FROM products WHERE products.prod_name like 'yves%';匹配包含"yves"的记录(包括记录"yves") SELECT FROM products WHERE products.prod_name like '%yves%';匹配以"yves"结尾的记录(包括记录"yves",不包括记录"yves ",也就是yves后面有空格的记录,这里需要注意) SELECT * FROM products WHERE products.prod_name like '%yves';通配符使用: SELECT FROM products WHERE products.prod_name like '_yves'; 匹配结果为: 像"yyves"这样记录.SELECT FROM products WHERE products.prod*name like 'yves*'; 匹配结果为: 像"yvesHe"这样的记录.(一个下划线只能匹配一个字符,不能多也不能少)
  • [数据安全] SHA1算法实现及详解
    1 SHA1算法简介安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。2 术语和概念2.1位(Bit),字节(Byte)和字(Word)SHA1始终把消息当成一个位(bit)字符串来处理。本文中,一个“字”(Word)是32位,而一个“字节”(Byte)是8位。比如,字符串“abc”可以被转换成一个位字符串:01100001 01100010 01100011。它也可以被表示成16进制字符串: 0x616263.2.2 运算符和符号下面的逻辑运算符都被运用于“字”(Word)X^Y    = X, Y逻辑与X \/ Y   = X, Y逻辑或X XOR Y= X, Y逻辑异或~X     =   X逻辑取反X+Y定义如下:字 X 和 Y 代表两个整数 x 和y, 其中 0 <= x < 2^32 且 0 <= y < 2^32. 令整数z = (x + y) mod 2^32. 这时候 0 <= z < 2^32. 将z转换成字Z, 那么就是 Z = X + Y.循环左移位操作符Sn(X)。X是一个字,n是一个整数,0<=n<=32。Sn(X) = (X<<n)OR(X>>32-n)X<<n定义如下:抛弃最左边的n位数字,将各个位依次向左移动n位,然后用0填补右边的n位(最后结果还是32位)。X>>n是抛弃右边的n位,将各个位依次向右移动n位,然后在左边的n位填0。因此可以叫Sn(X)位循环移位运算3 SHA1算法描述在SHA1算法中,我们必须把原始消息(字符串,文件等)转换成位字符串。SHA1算法只接受位作为输入。假设我们对字符串“abc”产生消息摘要。首先,我们将它转换成位字符串如下:01100001 01100010 01100011―――――――――――――‘a’=97   ‘b’=98   ‘c’=99这个位字符串的长度为24。下面我们需要5个步骤来计算MD5。3.1 补位       消息必须进行补位,以使其长度在对512取模以后的余数是448。也就是说,(补位后的消息长度)%512 = 448。即使长度已经满足对512取模后余数是448,补位也必须要进行。       补位是这样进行的:先补一个1,然后再补0,直到长度满足对512取模后余数是448。总而言之,补位是至少补一位,最多补512位。还是以前面的“abc”为例显示补位的过程。原始信息: 01100001 01100010 01100011补位第一步:01100001 01100010 01100011 1                                                                首先补一个“1”补位第二步:01100001 01100010 01100011 10…..0                                                                然后补423个“0”我们可以把最后补位完成后的数据用16进制写成下面的样子61626380 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000现在,数据的长度是448了,我们可以进行下一步操作。3.2 补长度       所谓的补长度是将原始数据的长度补到已经进行了补位操作的消息后面。通常用一个64位的数据来表示原始消息的长度。如果消息长度不大于2^64,那么第一个字就是0。在进行了补长度的操作以后,整个消息就变成下面这样了(16进制格式)61626380 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 00000018如果原始的消息长度超过了512,我们需要将它补成512的倍数。然后我们把整个消息分成一个一个512位的数据块,分别处理每一个数据块,从而得到消息摘要。3.3 使用的常量一系列的常量字K(0), K(1), ... , K(79),如果以16进制给出。它们如下:Kt = 0x5A827999  (0 <= t <= 19)Kt = 0x6ED9EBA1 (20 <= t <= 39)Kt = 0x8F1BBCDC (40 <= t <= 59)Kt = 0xCA62C1D6 (60 <= t <= 79).3.4 需要使用的函数在SHA1中我们需要一系列的函数。每个函数ft (0 <= t <= 79)都操作32位字B,C,D并且产生32位字作为输出。ft(B,C,D)可以如下定义ft(B,C,D) = (B AND C) or ((NOT B) AND D) ( 0 <= t <= 19)ft(B,C,D) = B XOR C XOR D              (20 <= t <= 39)ft(B,C,D) = (B AND C) or (B AND D) or (C AND D) (40 <= t <= 59)ft(B,C,D) = B XOR C XOR D                     (60 <= t <= 79).3.5 计算消息摘要必须使用进行了补位和补长度后的消息来计算消息摘要。计算需要两个缓冲区,每个都由5个32位的字组成,还需要一个80个32位字的缓冲区。第一个5个字的缓冲区被标识为A,B,C,D,E。第一个5个字的缓冲区被标识为H0, H1, H2, H3, H4。80个字的缓冲区被标识为W0, W1,..., W79另外还需要一个一个字的TEMP缓冲区。为了产生消息摘要,在第4部分中定义的16个字的数据块M1, M2,..., Mn会依次进行处理,处理每个数据块Mi 包含80个步骤。在处理每个数据块之前,缓冲区{Hi} 被初始化为下面的值(16进制)H0 = 0x67452301H1 = 0xEFCDAB89H2 = 0x98BADCFEH3 = 0x10325476H4 = 0xC3D2E1F0.现在开始处理M1, M2, ... , Mn。为了处理 Mi,需要进行下面的步骤(1). 将 Mi 分成 16 个字 W0, W1, ... , W15,  W0 是最左边的字(2). 对于 t = 16 到 79 令 Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).(3). 令 A = H0, B = H1, C = H2, D = H3, E = H4.(4) 对于 t = 0 到 79,执行下面的循环TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;E = D; D = C; C = S30(B); B = A; A = TEMP;(5). 令 H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.在处理完所有的 Mn, 后,消息摘要是一个160位的字符串,以下面的顺序标识H0 H1 H2 H3 H4.对于SHA256,SHA384,SHA512。你也可以用相似的办法来计算消息摘要。对消息进行补位的算法完全是一样的。
  • [技术干货] SQL注入、表达式注入、命令注入原理介绍
     SQL注入什么是SQL注入 程序中如果使用了未经校验的外部输入来构造SQL语句访问数据库,就很可能引入SQL注入漏洞。攻击者可以通过构造恶意输入来改变原本的SQL逻辑或者执行额外的SQL语句。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生SQL注入。攻击原理攻击者会将一些恶意代码插入到字符串中。然后会通过各种手段将该字符串传递到数据库的实例中进行分析和执行。只要这个恶意代码符合SQL语句的规则,在代码编译与执行的时候,就不会被系统所发现。攻击者可以通过SQL注入绕过程序原有逻辑执行恶意SQL达到不法的目的。 示例用户名:tom    密码:321 正常输入:  name=tom&pwd=321后端SQL: SELECT * FROM db_user WHERE NAME = 'tom' AND pwd = '321'恶意输入:  name=tom’ or ‘1’ = ‘1 &pwd=111后端SQL: SELECT * FROM db_user WHERE NAME = 'tom' OR 1 = 1 AND pwd = '111' 我们可以从上面的例子看出,只要tom是有效的用户,SQL注入就可以绕开密码的验证,攻击者还可以通过通过构造恶意输入来执行代码原有逻辑以外的SQL,比如通过传入name=tom';drop table db_user-- 如果程序执行了该语句,后果可想而知后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样语句永远都--能正确执行,用户轻易骗过系统,获取合法身份  如何防御 检查变量数据类型和格式固定格式的变量,比如数字,日期,邮箱,手机号等变量在SQL语句执行前严格的校验变量格式,确保变量格式规范,这样很大程度可以避免SQL注入攻击过滤特殊符号,sql语句无固定格式的变量在SQL语句执行前可以做一些特殊符号和sql语句的过滤,比如 ;,--,OR,AND等使用预编译语句a).使用PrepareStatement和占位符通过预编译sql语句防止sql注入(预编译的sql语句会带着?占位符进行编译,恶意的攻击参数无法改变已经编译好的sql语句逻辑)b). mybatis使用#{ }   (#{ }会预编译,${ }则直接进行变量替换操作)          2      表达式注入什么是表达式Java统一表达式语言(英语:Unified Expression Language,简称JUEL)是一种特殊用途的编程语言,主要在Java Web应用程序用于将表达式嵌入到web页面。Java规范制定者和Java Web领域技术专家小组制定了统一的表达式语言。JUEL最初包含在JSP 2.1规范JSR-245中,后来成为Java EE 7的一部分,改在JSR-341中定义。Java中表达式根据框架分为好多种OGNL- 一个被WebWork和Apache Struts 2使用的开源的表达式语言。MVEL- 一个被众多Java项目使用的开源的表达式语言。Apache Commons JEXL - 一个旨在促进Java项目实现动态和脚本功能的开源的表达式语言。SpEL - Spring表达式语言,一个开源的EL表达式语言,是Spring Framework的一部分。它主要用于Spring portfolio项目,但也可以用于其他项目。 (摘自维基百科,https://zh.wikipedia.org/wiki/%E7%BB%9F%E4%B8%80%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%AD%E8%A8%80)  什么是表达式注入 表达式根据框架分为好多种,但表达式注入的原理基本一样,表达式全部或部份外部可控从而让使用者可以通过表达式达到程序设计功能以外的能力,恶意攻击者可以通过表达式注入达到一些不法目的。  示例表达式根据框架分为好多种,这里以SpEL表达式为例。Spring Expression Language(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于Unified EL,但提供了额外的功能,特别是方法调用和基本的字符串模板功能。同时因为SpEL是以API接口的形式创建的,所以允许将其集成到其他应用程序和框架中。SpEL是Spring框架中的一种语言表达式,类似于Struts2中的OGNL。  SpEL使用 #{…} 作为定界符,所有在大括号中的字符都将被认为是 SpEL表达式,我们可以在其中使用运算符,变量以及引用bean,属性和方法如:引用其他对象:#{car}引用其他对象的属性:#{car.brand}调用其它方法 , 还可以链式操作:#{car.toString()}调用其它方法 , 还可以链式操作:#{car.toString()}调用静态方法静态属性:#{T(java.lang.Math).PI}SpEL还支持许多运算符,如:算术运算符:+,-,*,/,%,^(加号还可以用作字符串连接)比较运算符:< , > , == , >= , <= , lt , gt , eg , le , ge逻辑运算符:and , or , not , |if-else 运算符(类似三目运算符):?:(temary), ?:(Elvis)正则表达式:#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}  图中的spel接口直接将用户输入的参数作为表达式内容进行解析,这就造成了表达式外部可控,用户可以通过input参数进行表达式注入输入   input=new ProcessBuilder("calc").start()系统执行用户传入的命令,打开了计算器。 也可以采用T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性,也是可以实现相同的功能。输入   input=T(java.lang.Math).random()常见的命令注入payload${12*12}T(java.lang.Runtime).getRuntime().exec("")T(Thread).sleep(10000)"".getClass().forName('java.lang.Runtime').getRuntime().exec("")new java.lang.ProcessBuilder({""}).start()原理SpEL内部使用了反射,可以直接获得对象的属性信息,如果SpEL表达式外部可控,同样用户可以通过表达式执行精心构造的任意代码,导致命令执行。  如何防御 尽量避免使用外部输入的内容作为EL表达式内容通过参数白名单或者黑名单控制参数的合法性如果涉及到执行表达式的方法传入的参数外部可控,就存在表达式注入的安全风险,需要通过白名单参数校验来限制 如果是java程序,需搜索检查如下关键类方法el.ExpressionFactory.createValueExpression()javax.el.ValueExpression.getValue() 指定正确EvaluationContext(针对SpEL表达式注入)Spring官方推出了SimpleEvaluationContext作为安全类来防御该类漏洞,SimpleEvaluationContext旨在仅支持SpEL语言语法的一个子集。它不包括 Java类型引用,构造函数和bean引用,指定正确EvaluationContext,是防止SpEl表达式注入漏洞产生的首选。    3      命令注入 什么是命令注入是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。在Web应用中,有时候会用到一些命令执行的函数,比如java的java.lang Runtime. Exec,php中system、exec、shell_exec等,当用户能够控制这些函数中的参数时,就可以将恶意参系统命令拼接到正常命令中,从而造成命令注入攻击 示例 输入:input=ipconfig 结果:这是一个非常简单的命令注入的例子,用户通过接口传入的参数没有经过任何处理就直接被Runtime的exec方法执行,实际上发生的命令注入漏洞时命令来源通常比较复杂,可能是程序读取的文件或是系统参数可以被用户修改,也可能是直接或是间接传入的参数,还有根据用户传入的参数进行命令拼接的。但是发生命令注入根本原因是一样的--程序执行的命令是用户可控的,通过命令的执行,应用程序会授予攻击者一种原本不该拥有的特权或能力 如果攻击者能通过命令注入漏洞获取直接执行系统命令的能力,那他基本可以获取程序拥有的所有权限,危害可想而知。   如何防御选择不调用系统命令的实现方法保证所有命令行参数的来源可控,不使用用户传入数据或者用户可以控制的数据做命令来源严格校验参数,可以使用黑白名单校验的方式控制命令的范围降低程序的权限, 参考http://rui0.cn/archives/1043https://blog.csdn.net/qq_31481187/article/details/108025512https://blog.csdn.net/weixin_41679427/article/details/110310166?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_v2~rank_aggregation-2-110310166.pc_agg_rank_aggregation&utm_term=%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E&spm=1000.2123.3001.4430  
  • [技术干货] 集合操作符
    Union : 不包含重复值,默认按第一个查询的第一列升序排列。Union All : 完全并集包含重复值。不排序。Minus 不包含重复值,不排序。
总条数:140 到第
上滑加载中