libxml解析xml文件的一些总结

介绍:XML 和 DOM
libxml
介绍 数据类型 — xmlChar数据结构 创建 XML 文档解析 XML 文档修改 xml 文档
Xpath — 处理大型 XML 文档libxml2 库函数
要注意的函数读取 xml 文件xml 操作基本结构及其指针类型根节点相关函数 创建子节点相关函数添加子节点相关函数属性相关函数

参考

  1. http://xmlsoft.org/
  2. http://www.miidoo.cn/info_detail-204.html
  3. http://www.blogjava.net/wxb_nudt/archive/2007/11/28/161340.html
  4. http://www.ibm.com/developerworks/cn/aix/library/au-libxml2.html
  5. http://www.cppblog.com/lymons/archive/2009/03/30/37553.html
  6. XPath 教程

XML

介绍:XML 和 DOM

XML是eXtensible Markup Language的缩写,它是一种可扩展性标识语言, 能够让你自己创造标识,标识你所表示的内容。DOM全称是Document Object Model(文档对象模型),定义了一组与平台和语言无关的接口,以便程序和脚本能够动态访问和修改XML文档内容、结构及样式。XML创建了标识,而 DOM的作用就是告诉程序如何操作和显示这些标识。

XML将数据组织成为一棵树,DOM通过解析XML文档,为XML文档在逻辑上建立一个树模型,树的节点是一个个的对象。这样通过操作这棵树和这些对象就可以完成对XML文档的操作,为处理文档的所有方面提供了一个完美的概念性框架。

XML 中共有12种节点类型,其中最常见的节点类型有5种:

元素
元素是 XML 的基本组成单元。,描述XML的基本信息。
属性
属性节点包含关于元素节点的信息,通常包含在元素里面,描述元素的属性。
文本
包含许多文本信息或者只是空白。
文档
文档节点是整个文档中所有其它节点的父节点。
注释
注释是对相关的信息进行描述、注释。

libxml

介绍

本文所介绍的 libxml 是针对 C 语言的一套 API 接口。其他如 ruby,python 亦有对应的基于 libxml 开发的绑定库接口。

数据类型 — xmlChar

在 libXml 中用 xmlChar 替代 char , XML 使用 UTF-8 编码的一字节字符串。如果你的数据使用其它编码,它必须被转换到 UTF-8 才能使用libxml的函数。

如同标准 C 中的 char 类型一样, xmlChar 也有动态内存分配、字符串操作等相关函数。例如 xmlMalloc 是动态分配内存的函数; xmlFree 是配套的释放内存函数; xmlStrcmp 是字符串比较函数等等。基本上 xmlChar 字符串相关函数都在xmlstring.h 中定义;而动态内存分配函数在 xmlmemory.h 中定义。另外要注意,因为总是要在 xmlChar* 和 char* 之间进行类型转换,所以定义了一个宏 BAD_CAST ,其定义如下: xmlstring.h

#define BAD_CAST (xmlChar *)

原则上来说, unsigned char 和 char 之间进行强制类型转换是没有问题的。

数据结构

xmlDoc
代表DOM结构中的文档类型。包含由解析文档建立的树结构, xmlDocPtr 是指向这个结构的指针。
xmlNode
代表DOM结构中的除文档类型类型外的其它节点类型。包含单一结点的结构, xmlNodePtr 是指向这个结构的指针,它被用于遍历文档树。节点应该是xml中最重要的元素了, xmlNode 代表了xml文档中的一个节点,实现为一个 struct ,内容很丰富: tree.h
typedef struct _xmlNode xmlNode;
typedef xmlNode *xmlNodePtr;
struct _xmlNode {
void           *_private;/* application data */
xmlElementType   type;   /* type number, must be second ! */
const xmlChar   *name;      /* the name of the node, or the entity */
struct _xmlNode *children; /* parent->childs link */
struct _xmlNode *last;   /* last child link */
struct _xmlNode *parent;/* child->parent link */
struct _xmlNode *next;   /* next sibling link */
struct _xmlNode *prev;   /* previous sibling link */
struct _xmlDoc *doc;/* the containing document */
/* End of common part */
xmlNs           *ns;        /* pointer to the associated namespace */
xmlChar         *content;   /* the content */
struct _xmlAttr *properties;/* properties list */
xmlNs           *nsDef;     /* namespace definitions on this node */
void            *psvi;/* for type/PSVI informations */
unsigned short   line;   /* line number */
unsigned short   extra; /* extra data for XPath/XSLT */
};

可以看到,节点之间是以链表和树两种方式同时组织起来的,next和prev指针可以组成链表,而parent和children可以组织为树。所有节点都是文档 xmlDoc 节点的直接或间接子节点。同时还有以下重要元素:

  • 节点中的文字内容: content ;
  • 节点所属文档: doc ;
  • 节点名字: name ;
  • 节点的 namespace: ns ;
  • 节点属性列表: properties ;

xml 文档的操作其根本原理就是在节点之间移动、查询节点的各项信息,并进行增加、删除、修改的操作。 xmlDocSetRootElement 函数可以将一个节点设置为某个文档的根节点,这是将文档与节点连接起来的重要手段,当有了根结点以后,所有子节点就可以依次连接上根节点,从而组织成为一个 xml 树。

创建 XML 文档

创建一个 XML 文档流程如下:

  1. 用 xmlNewDoc 函数创建一个文档指针 doc;
  2. 用 xmlNewNode 函数创建一个节点指针 root_node;
  3. 用 xmlDocSetRootElement 将 root_node 设置为 doc 的根节点;
  4. 给 root_node 添加一系列子节点,并设置字节点的内容和属性;
  5. 用 xmlSaveFile 保存 xml 到文件;
  6. 用 xmlFreeDoc 函数关闭文档指针,清除内存。

示例

下面用一个例子说明一些函数的使用,和创建一个 XML 文档的大致步骤:

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
int main (int argc, char **argv)
{
xmlDocPtr pdoc = NULL;
xmlNodePtr proot_node = NULL,pnode = NULL,pnode1 = NULL;
// 创建一个新文档并设置 root 节点
  // 一个 XML 文件只有一个 root 节点
  pdoc = xmlNewDoc (BAD_CAST "1.0");
proot_node = xmlNewNode (NULL, BAD_CAST "根节点");
xmlNewProp (proot_node, BAD_CAST "版本", BAD_CAST "1.0");
xmlDocSetRootElement (pdoc, proot_node);
pnode = xmlNewNode (NULL, BAD_CAST "子节点1");
// 创建上面 pnode 的子节点
  xmlNewChild (pnode, NULL, BAD_CAST "子子节点1", BAD_CAST "信息");
// 添加子节点到 root 节点
  xmlAddChild (proot_node, pnode);
pnode1 = xmlNewNode (NULL, BAD_CAST "子子节点1");
xmlAddChild (pnode, pnode1);
xmlAddChild (pnode1,xmlNewText (BAD_CAST "这是更低的节点,子子子节点1"));
// 还可以这样直接创建一个子节点到 root 节点上
  xmlNewTextChild (proot_node, NULL, BAD_CAST "子节点2", BAD_CAST "子节点2的内容");
xmlNewTextChild (proot_node, NULL, BAD_CAST "子节点3", BAD_CAST "子节点3的内容");
// 保存 xml 为文件,如果没有给出文件名参数,就输出到标准输出
  xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);
// 释放资源
  xmlFreeDoc (pdoc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

编译这个例子,先看看系统里面的 libxml2 库的 pkgconfig 信息:

root@jianlee:~/lab/xml# cat /usr/lib/pkgconfig/libxml-2.0.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=1
Name: libXML
Version: 2.6.32
Description: libXML library version2.
Requires:
Libs: -L${libdir} -lxml2
Libs.private:  -lz  -lm
Cflags: -I${includedir}/libxml2
root@jianlee:~/lab/xml# pkg-config libxml-2.0 --cflags --libs
-I/usr/include/libxml2  -lxml2

编译:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` create_xml.c

如果没有修改源程序,输出应该是这样:

root@jianlee:~/lab/xml# ./a.out
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
<子节点1>
<子子节点1>信息</子子节点1>
<子子节点1>这是更低的节点,子子子节点1</子子节点1>
</子节点1>
<子节点2>子节点2的内容</子节点2>
<子节点3>子节点3的内容</子节点3>
</根节点>

示例补充说明

输出的各节点不要在一行

上面使用下面方式保存 xml 文档,输出的文件各子节点间自动加入回车:

  // 保存 xml 为文件,如果没有给出文件名参数,就输出到标准输出
xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

如果把上面的 1 换成 0 ,输出格式是放在一行。

用到的函数说明

上面涉及几个函数和类型定义,不过意思很明了,下面解释一个(重要的是自己动手写程序,反复实验,所谓熟能生巧)。

xmlDocPtr
指向 XML 文档对象的指针
xmlNodePtr
指向 XML 文档对象中的节点对象(根节点和子节点都是一样的)
xmlNewDoc
创建一个 XML 文档对象
xmlNewNode
创建一个 XML 文档的指针对象
xmlNewProp
给一个节点增加属性信息,包括在 <> 中,如:
  xmlNewProp (proot_node, BAD_CAST "版本", BAD_CAST "1.0");

最后显示是这个样子:

<根节点 版本="1.0">
xmlDocSetRootElement
设置 XML 文档对象的根节点,只有一个根节点
xmlNewChild
指定一个节点,会创建这个节点的子节点。这样不需要使用 xmlNewNode 创建一个节点,再使用 xmlAddChild 添加到其父节点中。
xmlAddChild
把一个节点设置为另外一个节点的子节点。
xmlNewText
创建一个描述节点,没有 <> 符号,需要添加到其他节点上。比如上例中的:
  xmlAddChild (pnode1,xmlNewText (BAD_CAST "这是更低的节点,子子子节点1"));

会出现下面的结果:

    <子子节点1>这是更低的节点,子子子节点1</子子节点1>
xmlNewTextChild
和 xmlNewText 的区别如同 xmlNewNodeChild 和 xmlNewNode 的区别一样!
xmlSaveFormatFileEnc
保存 xml 对象为文件。
xmlFreeDoc
释放 xml 对象
xmlCleanupParser
清理
xmlMemoryDump
清理

解析 XML 文档

解析一个xml文档,从中取出想要的信息,例如节点中包含的文字,或者某个节点的属性,其流程如下:

  • 用 xmlReadFile 函数读出一个文档指针 doc ;
  • 用 xmlDocGetRootElement 函数得到根节点 curNode ;
  • curNode->xmlChildrenNode 就是根节点的子节点集合 ;
  • 轮询子节点集合,找到所需的节点,用 xmlNodeGetContent 取出其内容 ;
  • 用 xmlHasProp 查找含有某个属性的节点 ;
  • 取出该节点的属性集合,用 xmlGetProp 取出其属性值 ;
  • 用 xmlFreeDoc 函数关闭文档指针,并清除本文档中所有节点动态申请的内存。

注意: 节点列表的指针依然是 xmlNodePtr ,属性列表的指针也是 xmlAttrPtr ,并没有 xmlNodeList 或者 xmlAttrList 这样的类型 。看作列表的时候使用它们的 next 和 prev 链表指针来进行轮询 。只有在 Xpath 中有 xmlNodeSet 这种类型。

示例

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
int main (int argc , char **argv)
{
xmlDocPtr     pdoc = NULL;
xmlNodePtr    proot = NULL, curNode = NULL;
char *psfilename;
if (argc < 1)
{
printf ("用法: %s xml文件名\n", argv[0]);
exit (1);
}
psfilename = argv[1];
// 打开 xml 文档
  //xmlKeepBlanksDefault(0);
  pdoc = xmlReadFile (psfilename, "UTF-8", XML_PARSE_RECOVER);
if (pdoc == NULL)
{
printf ("打开文件 %s 出错!\n", psfilename);
exit (1);
}
// 获取 xml 文档对象的根节对象
  proot = xmlDocGetRootElement (pdoc);
if (proot == NULL)
{
printf("错: %s 是空文档(没有root节点)!\n", psfilename);
exit (1);
}
/* 我使用上面程序创建的 xml 文档,它的根节点是“根节点”,这里比较是否
正确。*/
if (xmlStrcmp (proot->name, BAD_CAST "根节点") != 0)
{
printf ("错误文档" );
exit (1);
}
/* 如果打开的 xml 对象有 version 属性,那么就输出它的值。 */
if (xmlHasProp (proot, BAD_CAST "版本"))
{
xmlChar *szAttr = xmlGetProp (proot, BAD_CAST "版本");
printf ("版本: %s \n根节点:%s\n" , szAttr, proot->name);
}
else
{
printf (" xml 文档没有版本信息\n");
}
curNode = proot->xmlChildrenNode;
char n=0;
while (curNode != NULL)
{
if (curNode->name != BAD_CAST "text")
{
printf ("子节点%d: %s\n", n++,curNode->name);
}
curNode = curNode->next;
}
/* 关闭和清理 */
xmlFreeDoc (pdoc);
xmlCleanupParser ();
return 0;
}

编译运行(使用上例创建的 my.xml 文件):

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
<子节点1>
<子子节点1>信息</子子节点1>
<子子节点1>这是更低的节点,子子子节点1</子子节点1>
</子节点1>
<子节点2>子节点2的内容</子节点2>
<子节点3>子节点3的内容</子节点3>
</根节点>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根节点:根节点
子节点0: text
子节点1: 子节点1
子节点2: text
子节点3: 子节点2
子节点4: text
子节点5: 子节点3
子节点6: text

为什么 my.xml 文件中显示只有 ”子节点1“、 ”子节点2“和 “子节点3”三个子节点,而程序显示有 7 个子节点呢?!而且 0、2、4、6 都是 text 名字?

这是因为其他四个分别是元素前后的空白文本符号,而 XML 把它们也当做一个 Node !元素是 Node 的一种类型。XML 文档对象模型 (DOM) 定义了几种不同的 Nodes 类型,包括 Elements(如 files 或者 age)、Attributes(如 units)和 Text(如 root 或者 10)。元素可以具有子节点。

在打开 xml 文档之前加上一句(取消上面程序中的此句注释就可以):

  xmlKeepBlanksDefault(0);

或者使用下面参数读取 xml 文档:

//读取xml文件时忽略空格
doc = xmlReadFile(docname, NULL, XML_PARSE_NOBLANKS);

这样就可以按我们所想的运行了:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根节点:根节点
子节点0: 子节点1
子节点1: 子节点2
子节点2: 子节点3

还有一点注意: my.xml 文件中的子节点名字一次是 “子节点1”、“子节点2”、 “子节点3”。程序中的 n 值确是从 0 开始计算。从 0 还是 1 是个人喜好。我有时候喜好从 0 开始,有时候喜好从 1 开始。

xmlFreeDoc
释放文档指针。特别注意,当你调用 xmlFreeDoc 时,该文档所有包含的节点内存都被释放,所以一般来说不需要手动调用 xmlFreeNode 或者 xmlFreeNodeList 来释放动态分配的节点内存,除非你把该节点从文档中移除了。一般来说,一个文档中所有节点都应该动态分配,然后加入文档,最后调用 xmlFreeDoc 一次释放所有节点申请的动态内存,这也是为什么我们很少看见 xmlNodeFree 的原因。
xmlSaveFile
将文档以默认方式存入一个文件。
xmlSaveFormatFileEnc
可将文档以某种编码/格式存入一个文件中,创建 xml 文档是的示例中用到

修改 xml 文档

首先打开一个已经存在的xml文档,顺着根结点找到需要添加、删除、修改的地方,调用相应的xml函数对节点进行增、删、改操作。

删除节点

删除节点使用下面方法:

if (!xmlStrcmp(curNode->name, BAD_CAST "newNode1"))
{
xmlNodePtr tempNode;
tempNode = curNode->next;
xmlUnlinkNode(curNode);
xmlFreeNode(curNode);
curNode = tempNode;
continue;
}

即将当前节点从文档中断链(unlink),这样本文档就不会再包含这个子节点。这样做需要使用一个临时变量来存储断链节点的后续节点,并记得要手动删除断链节点的内存。

示例

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
int main(int argc, char* argv[])
{
xmlDocPtr doc;   //定义解析文档指针
  xmlNodePtr curNode;  //定义结点指针(你需要它为了在各个结点间移动)
  char *szDocName;
if (argc <= 1)
{
printf("Usage: %s docname\n", argv[0]);
return(0);
}
szDocName = argv[1];
xmlKeepBlanksDefault(0);
doc = xmlReadFile(szDocName,"UTF-8",XML_PARSE_RECOVER);  //解析文件

if (NULL == doc)
{
fprintf(stderr,"Document not parsed successfully. \n");
return -1;
}
curNode = xmlDocGetRootElement(doc);
/*检查确认当前文档中包含内容*/
if (NULL == curNode)
{
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return -1;
}
curNode = curNode->children;
while (NULL != curNode)
{
//删除 "子节点1"
      if (!xmlStrcmp(curNode->name, BAD_CAST "子节点1"))
{
xmlNodePtr tempNode;
tempNode = curNode->next;
xmlUnlinkNode(curNode);
xmlFreeNode(curNode);
curNode = tempNode;
continue;
}
//修改 "子节点2" 的属性值
      if (!xmlStrcmp(curNode->name, BAD_CAST "子节点2"))
{
xmlSetProp(curNode,BAD_CAST "属性1", BAD_CAST "设置");
}
//修改 “子节点2” 的内容
      if (!xmlStrcmp(curNode->name, BAD_CAST "子节点2"))
{
xmlNodeSetContent(curNode, BAD_CAST "内容变了");
}
//增加一个属性
      if (!xmlStrcmp(curNode->name, BAD_CAST "子节点3"))
{
xmlNewProp(curNode, BAD_CAST "新属性", BAD_CAST "有");
}
//增加 "子节点4"
      if (!xmlStrcmp(curNode->name, BAD_CAST "子节点3"))
{
xmlNewTextChild(curNode, NULL, BAD_CAST "新子子节点1", BAD_CAST "新内容");
}
curNode = curNode->next;
}
//  保存文件
  xmlSaveFormatFileEnc (szDocName, doc,"UTF-8",1);
xmlFreeDoc (doc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

编译运行:

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
<子节点1>
<子子节点1>信息</子子节点1>
<子子节点1>这是更低的节点,子子子节点1</子子节点1>
</子节点1>
<子节点2>子节点2的内容</子节点2>
<子节点3>子节点3的内容</子节点3>
</根节点>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` modify_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
<子节点2 属性1="设置">内容变了</子节点2>
<子节点3 新属性="有">子节点3的内容<新子子节点1>新内容</新子子节点1></子节点3>
</根节点>
root@jianlee:~/lab/xml# ./a.out my.xml  # 看看再运行一次的结果!
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
<子节点2 属性1="设置">内容变了</子节点2>
<子节点3 新属性="有" 新属性="有">子节点3的内容<新子子节点1>新内容</新子子节点1><新子子节点1>新内容</新子子节点1></子节点3>
</根节点>

Xpath — 处理大型 XML 文档

libxml2 库函数

要注意的函数

xmlKeepBlanksDefault

int xmlKeepBlanksDefault (int val)

设置是否忽略空白节点,比如空格,在分析前必须调用,默认值是0,最好设置成1.

xmlKeepBlanksDefault(0) 除了在读入xml文件时忽略空白之外,还会在写出xml 文件时在每行前面放置缩进(indent)。如果使用xmlKeepBlanksDefault(1) 则你会发现每行前面的缩进就没有了,但不会影响回车换行。

xmlSaveFormatFile

  // 保存 xml 为文件,如果没有给出文件名参数,就输出到标准输出
xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

xmlSaveFormatFile 的 format 参数设置成 0,保存后的 xml 文档里是会把所有的结点都放到一行里显示。设置为 1,就可以自动添加回车。

读取 xml 文件

xmlParseFile

xmlDocPtr xmlParseFile (const char * filename)

以默认方式读入一个 UTF-8 格式的 xml 文档, 并返回一个文档对象指针 <libxml/tree.h>

xmlReadFile

指定编码读取一个 xml 文档,返回指针。

xml 操作基本结构及其指针类型

xmlDoc, xmlDocPtr

文档对象的结构体及其指针

xmlNode, xmlNodePtr

节点对象的结构体及其指针

xmlAttr, xmlAttrPtr

节点属性的结构体及其指针

xmlNs, xmlNsPtr

节点命名空间的结构及其指针

根节点相关函数

xmlDocGetRootElement

xmlNodePtr xmlDocGetRootElement (xmlDocPtr doc)
获取文档根节点

xmlDocSetRootElement

xmlNodePtr xmlDocSetRootElement (xmlDocPtr doc, xmlNodePtr root)
设置文档根节点

创建子节点相关函数

xmlNewNode

xmlNodePtr xmlNewNode (xmlNsPtr ns, const xmlChar * name)
创建新节点

xmlNewChild

xmlNodePtr xmlNewChild (xmlNodePtr parent, xmlNsPtr ns, const xmlChar * name, const xmlChar * content)
创建新的子节点

xmlCopyNode

xmlNodePtr xmlCopyNode (const xmlNodePtr node, int extended)
复制当前节点

添加子节点相关函数

xmlAddChild

xmlNodePtr xmlAddChild (xmlNodePtr parent, xmlNodePtr cur)
给指定节点添加子节点

xmlAddNextSibling

xmlNodePtr xmlAddNextSibling (xmlNodePtr cur, xmlNodePtr elem)
添加后一个兄弟节点

xmlAddPrevSibling

xmlNodePtr xmlAddPrevSibling (xmlNodePtr cur, xmlNodePtr elem)
添加前一个兄弟节点

xmlAddSibling

xmlNodePtr xmlAddSibling (xmlNodePtr cur, xmlNodePtr elem)
添加兄弟节点

属性相关函数

xmlNewProp

xmlAttrPtr xmlNewProp (xmlNodePtr node, const xmlChar * name, const xmlChar * value)
创建新节点属性

xmlGetProp

xmlChar * xmlGetProp (xmlNodePtr node, const xmlChar * name)
读取节点属性

xmlSetProp

xmlAttrPtr xmlSetProp (xmlNodePtr node, const xmlChar * name, const xmlChar * value)
设置节点属性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux(7)-正则表达式

正则表达式demo1:在某个文件中寻找命令seddemo2:寻找8位电话号码正则表达式&#xff1a;用来描述或者匹配某一系列符合某个句法队则的字符串或者单个字符串。最初正则表达式&#xff0c;出现在自动控制理论和形式化语言理论中。 Linux 中 find grep sed ls命令都支持正则表达式…

服务器端开发的一些建议

摘要: 本文作为游戏服务器端开发的基本大纲&#xff0c;是游戏实践开发中的总结。第一部分专业基础&#xff0c;用于指导招聘和实习考核&#xff0c; 第二部分游戏入门&#xff0c;讲述游戏服务器端开发的基本要点&#xff0c;第三部分服务端架构&#xff0c;介绍架构设计中的一…

leetcode63 不同路径II

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为“Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为“Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到右下角将…

小谈Online-game服务器端设计(1、2)

谈这个话题之前&#xff0c;首先要让大家知道&#xff0c;什么是服务器。在网络游戏中&#xff0c;服务器所扮演的角色是同步&#xff0c;广播和服务器主动的一些行为&#xff0c;比如说天气&#xff0c;NPC AI之类的&#xff0c;之所以现在的很多网络游戏服务器都需要负担一些…

Linux(8)-Linux下的编程开发-C/C++、PHP、JAVA概述

Linux下的编程开发1.C/C语言开发环境的搭建2.PHP开发环境搭建3.JAVA开发环境搭建1.C/C语言开发环境的搭建 方式1:文本编辑器编译器&#xff08;gcc/g&#xff09; Ubuntu 下常用的文本编辑器&#xff1a; Gedit–语法高亮Vim–vi(无比强大无比难用)的改进。字符界面/图形界面…

leetcode55 跳跃游戏 秒杀所有答案

给定一个非负整数数组&#xff0c;你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例 1: 输入: [2,3,1,1,4] 输出: true 解释: 我们可以先跳 1 步&#xff0c;从位置 0 到达 位置 1, 然后再从位置 …

小谈Online-game服务器端设计(3)

下面我想来谈谈关于服务器上NPC的设计以及NPC智能等一些方面涉及到的问题。首先&#xff0c;我们需要知道什么是NPC&#xff0c;NPC需要做什么。NPC的全称是&#xff08;Non-Player Character&#xff09;&#xff0c;很显然&#xff0c;他是一个character&#xff0c;但不是玩…

小谈Online-game服务器端设计(4)

在这一章节&#xff0c;我想谈谈关于服务器端的脚本的相关设计。因为在上一章节里面&#xff0c;谈NPC智能相关的时候已经接触到一些脚本相关的东东了。还是先来谈谈脚本的作用吧。   在基于编译的服务器端程序中&#xff0c;是无法在程序的运行过程中构建一些东西的&#xf…

leetcode45 跳跃游戏II 秒杀所有答案

给定一个非负整数数组&#xff0c;你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 示例: 输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 …

MachineLearning(7)-决策树基础+sklearn.DecisionTreeClassifier简单实践

sklearn.DecisionTreeClassifier决策树简单使用1.决策树算法基础2.sklearn.DecisionTreeClassifier简单实践2.1 决策树类2.3 决策树构建2.3.1全数据集拟合&#xff0c;决策树可视化2.3.2交叉验证实验2.3.3超参数搜索2.3.4模型保存与导入2.3.5固定随机数种子参考资料1.决策树算法…

游戏服务器体系结构

本文描述了一个我所设计的游戏服务器体系结构,其目的是实现游戏服务器的动态负载平衡,将对象从繁忙的服务器转移到相对空闲的服务器中.设计并没有经过具体的测试与验证,仅仅是将自己目前的一些想法记录下来.随着新构思的出现,可能会有所变化. 以下是服务器的逻辑视图,其中忽略…

游戏服务器架构探讨

要描述一项技术或是一个行业&#xff0c;一般都会从其最古老的历史开始说起&#xff0c;我本也想按着这个套路走&#xff0c;无奈本人乃一八零后小辈&#xff0c;没有经历过那些苦涩的却令人羡慕的单机游戏开发&#xff0c;也没有响当当的拿的出手的优秀作品&#xff0c;所以也…

leetcode72 编辑距离

给定两个单词 word1 和 word2&#xff0c;计算出将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符 删除一个字符 替换一个字符 示例 1: 输入: word1 "horse", word2 "ros" 输出: 3 解释: ho…

即时通讯系统架构

有过几款IM系统开发经历&#xff0c;目前有一款还在线上跑着。准备简单地介绍一下大型商业应用的IM系统的架构。设计这种架构比较重要的一点是低耦合&#xff0c;把整个系统设计成多个相互分离的子系统。我把整个系统分成下面几个部分&#xff1a;&#xff08;1&#xff09;状态…

leetcode303 区域和检索

给定一个整数数组 nums&#xff0c;求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和&#xff0c;包含 i, j 两点。 示例&#xff1a; 给定 nums [-2, 0, 3, -5, 2, -1]&#xff0c;求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0,…

算法(24)-股票买卖

股票买卖1.动态规划框架LeetCode-121 一次买卖LeetCode-122 不限次数LeetCode-309 不限次数冷冻期LeetCode-714 不限次数手续费LeetCode-123 两次买卖LeetCode-188 k次买卖2.贪心特解LeetCode-121 一次买卖LeetCode-122 不限次数解题思路参考buladong解题&#xff0c;详细信息可…

网络游戏的客户端同步问题 .

有关位置同步的方案实际上已经比较成熟&#xff0c;网上也有比较多的资料可供参考。在《带宽限制下的视觉实体属性传播》一文中&#xff0c;作者也简单提到了位置同步方案的构造过程&#xff0c;但涉及到细节的地方没有深入&#xff0c;这里专门针对这一主题做些回顾。 最直接的…

leetcode319 灯泡的开关

初始时有 n 个灯泡关闭。 第 1 轮&#xff0c;你打开所有的灯泡。 第 2 轮&#xff0c;每两个灯泡你关闭一次。 第 3 轮&#xff0c;每三个灯泡切换一次开关&#xff08;如果关闭则开启&#xff0c;如果开启则关闭&#xff09;。第 i 轮&#xff0c;每 i 个灯泡切换一次开关。 …

网游服务器端设计思考:心跳设计

网络游戏服务器的主要作用是模拟整个游戏世界&#xff0c;客户端用过网络连接把一些信息数据发给服务器&#xff0c;在操作合法的情况下&#xff0c;更新服务器上该客户端对应的player实体、所在场景等&#xff0c;并把这些操作及其影响广播出去。让别的客户端能显示这些操作。…

算法(25)-括号

各种括号1.LeetCode-22 括号生成--各种括号排列组合2.LeetCode-20 有效括号(是否)--堆栈3.LeetCode-32 最长有效括号(长度)--dp4.LeetCode-301删除无效括号 --多种删除方式1.LeetCode-22 括号生成–各种括号排列组合 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&a…