目标:通过网上下载的OpenStreetMap.xml数据格式,将该文件的格式进行统计,清洗,并导出成CSV格式的文件,最后倒入到SQLite中

本案例中所需的包

import csv
import codecs
import pprint
import re
import xml.etree.cElementTree as ET
from collections import defaultdict
import cerberus
import schema

1.统计文件中每一个标签出现的次数

思路:将xml文件使用sax解析,将每一个节点的的标签值设为字典的key,次数为value,初始化为0,

   循环文件,如果可以找到key,那么value的值+1,否则不变

def count_tags(filename):
#1.读文件
osm = ET.ElementTree(file=filename)
#2.获取根节点
root = osm.getroot()
#3.获取根节点的标签,创建一个字典来存放标签名和次数
tags_count_dic = {root.tag:0}
#4.循环文件
for _,ele in ET.iterparse(filename,events=('start',)):
#5.如果有元素的tag在字典中,则value的值+1,否则表示该标签只出现一次
if ele.tag in tags_count_dic:
tags_count_dic[ele.tag] += 1
else:
tags_count_dic[ele.tag] = 1
return tags_count_dic
def test():
#测试函数的断言不出错,表示结果正确
tags = count_tags('example.osm')
pprint.pprint(tags)
assert tags == {'bounds': 1,
'member': 3,
'nd': 4,
'node': 20,
'osm': 1,
'relation': 1,
'tag': 7,
'way': 1} if __name__ == "__main__":
test()

2.根据正则表达式,确定各种标签类型的数量

思路:获取根据传入的element,来获取tag,获取到tag即可获取到k的值,在根据正则表达式进行匹配,将匹配成功的值放入到不同的字典中

lower = re.compile(r'^([a-z]|_)*$') #仅包含小写字母且有效的标记
lower_colon = re.compile(r'^([a-z]|_)*:([a-z]|_)*$') #名称中有冒号的其他有效标记
problemchars = re.compile(r'[=\+/&<>;\'"\?%#$@\,\. \t\r\n]') #字符存在问题的标记 def key_type(element,keys):
#1.找到需要处理的标签进行处理
if element.tag == 'tag':
#2.获取带匹配的字符串
key = element.attrib['k']
#逐次匹配,并将匹配成功的结果放到keys中,并返回
if lower.search(key):
keys['lower'] += 1
elif lower_colon.search(key):
keys['lower_colon'] += 1
elif problemchars.search(key):
keys['problemchars'] += 1
else:
keys['other'] += 1
return keys def process_map(filename):
keys = {"lower": 0, "lower_colon": 0, "problemchars": 0, "other": 0}
for _, element in ET.iterparse(filename):
keys = key_type(element, keys) return keys
def test():
#测试函数的断言不报错,代码正确
keys = process_map('example.osm')
pprint.pprint(keys)
assert keys == {'lower': 5, 'lower_colon': 0, 'other': 1, 'problemchars': 1} if __name__ == "__main__":
test()

3.搜索用户,返回一组唯一的用户ID

思路:找到uid所对应的tag,循环xml文件,如果标签存在uid,就加入到set中返回

def get_user(element):
#如果标签中包含'uid'这一属性,则返回该属性的值
if 'uid' in element.attrib:
return element.attrib['uid'] def process_map(filename):
users = set()
#循环xml文件,如果每行的元素中有'uid'这一标签,则其值取出加入到set中,返回
for _, element in ET.iterparse(filename):
if get_user(element):
users.add(get_user(element))
return users
def test():
#断言不出错,程序正确
users = process_map('example.osm')
pprint.pprint(users)
assert len(users) == 6 if __name__ == "__main__":
test()

4.完善街道名,将街道中的一些不合法的值去除

思路:循环街道的字典,名称在mapping,则进行替换,返回替换后的字符串

OSMFILE = "example1.osm"
street_type_re = re.compile(r'\b\S+\.?$', re.IGNORECASE) expected = ["Street", "Avenue", "Boulevard", "Drive", "Court", "Place", "Square", "Lane", "Road",
"Trail", "Parkway", "Commons"] # UPDATE THIS VARIABLE
#题目这里的字符串需要更改,否则结果错误
mapping = { "Rd.": "Road",
"St.": "Street",
"Ave": "Avenue"
} def audit_street_type(street_types,street_name):
m = street_type_re.search(street_name)
if m:
street_type = m.group()
if street_type not in expected:
street_types[street_type].add(street_name) def is_street_name(elem):
return (elem.attrib['k'] == 'addr:street') def audit(osmfile):
osm_file = open(osmfile,'r')
street_types = defaultdict(set)
for event,ele in ET.iterparse(osmfile,events=('start',)):
if ele.tag == 'tag' or ele.tag == 'way':
for tag in ele.iter('tag'):
if is_street_name(tag):
audit_street_type(street_types,tag.attrib['v'])
osm_file.close()
return street_types def update_name(name, mapping):
#获取需要修改的key
changewords = mapping.keys()
#如果名称相同,则替换字符,并返回
for word in changewords:
if word in name:
name = name.replace(word,mapping.get(word))
return name
def test():
#断言不出错,则结果正确
st_types = audit(OSMFILE)
assert len(st_types) == 3
pprint.pprint(dict(st_types))
for st_type, ways in st_types.iteritems():
for name in ways:
better_name = update_name(name, mapping)
print name, "=>", better_name
if name == "West Lexington St.":
assert better_name == "West Lexington Street"
if name == "Baldwin Rd.":
assert better_name == "Baldwin Road" if __name__ == "__main__":
test()

5.数据清洗

目标数据的结构

node节点需要[id,user,uid,version,lat,lon,timestamp,changeset]

node节点下的tags子节点需要[id,key,value,type]

{'node': {'id': 757860928,
'user': 'uboot',
'uid': 26299,
'version': '',
'lat': 41.9747374,
'lon': -87.6920102,
'timestamp': '2010-07-22T16:16:51Z',
'changeset': 5288876},
'node_tags': [{'id': 757860928,
'key': 'amenity',
'value': 'fast_food',
'type': 'regular'},
{'id': 757860928,
'key': 'cuisine',
'value': 'sausage',
'type': 'regular'},
{'id': 757860928,
'key': 'name',
'value': "Shelly's Tasty Freeze",
'type': 'regular'}]}

way节点需要[id,user,uid,version,timestamp,changeset]

way节点下的nodes子节点需要[id,node_id,position]

way节点下的tag子节点需要[id,key,value,type]

{'way': {'id': 209809850,
'user': 'chicago-buildings',
'uid': 674454,
'version': '',
'timestamp': '2013-03-13T15:58:04Z',
'changeset': 15353317},
'way_nodes': [{'id': 209809850, 'node_id': 2199822281, 'position': 0},
{'id': 209809850, 'node_id': 2199822390, 'position': 1},
{'id': 209809850, 'node_id': 2199822392, 'position': 2},
{'id': 209809850, 'node_id': 2199822369, 'position': 3},
{'id': 209809850, 'node_id': 2199822370, 'position': 4},
{'id': 209809850, 'node_id': 2199822284, 'position': 5},
{'id': 209809850, 'node_id': 2199822281, 'position': 6}],
'way_tags': [{'id': 209809850,
'key': 'housenumber',
'type': 'addr',
'value': ''},
{'id': 209809850,
'key': 'street',
'type': 'addr',
'value': 'West Lexington St.'},
{'id': 209809850,
'key': 'street:name',
'type': 'addr',
'value': 'Lexington'},
{'id': '',
'key': 'street:prefix',
'type': 'addr',
'value': 'West'},
{'id': 209809850,
'key': 'street:type',
'type': 'addr',
'value': 'Street'},
{'id': 209809850,
'key': 'building',
'type': 'regular',
'value': 'yes'},
{'id': 209809850,
'key': 'levels',
'type': 'building',
'value': ''},
{'id': 209809850,
'key': 'building_id',
'type': 'chicago',
'value': ''}]}

思路: 1.使用iterparse便利xml中每一个顶层标签

2.使用自定义函数将每个元素变成多个数据结构

3.利用架构和验证库保证数据格式的正确

4.将每个数据结构写入相应的csv文件

OSM_PATH = "example1.osm"

NODES_PATH = "nodes.csv"  #node标签生成的文件名
NODE_TAGS_PATH = "nodes_tags.csv" #node下的tag标签生成的文件名
WAYS_PATH = "ways.csv" #way标签生成的文件名
WAY_NODES_PATH = "ways_nodes.csv" #way标签下的node生成的文件名
WAY_TAGS_PATH = "ways_tags.csv" #way标签下的tag生成的文件名 LOWER_COLON = re.compile(r'^([a-z]|_)+:([a-z]|_)+') #字符串中有冒号和小写字母的标记
PROBLEMCHARS = re.compile(r'[=\+/&<>;\'"\?%#$@\,\. \t\r\n]')#字符存在问题的标记
SCHEMA = schema.schema #模板文件 # Make sure the fields order in the csvs matches the column order in the sql table schema
#每一个生成的文件的表头
NODE_FIELDS = ['id', 'lat', 'lon', 'user', 'uid', 'version', 'changeset', 'timestamp']
NODE_TAGS_FIELDS = ['id', 'key', 'value', 'type']
WAY_FIELDS = ['id', 'user', 'uid', 'version', 'changeset', 'timestamp']
WAY_TAGS_FIELDS = ['id', 'key', 'value', 'type']
WAY_NODES_FIELDS = ['id', 'node_id', 'position'] def shape_element(element, node_attr_fields=NODE_FIELDS, way_attr_fields=WAY_FIELDS,
problem_chars=PROBLEMCHARS, default_tag_type='regular'):
"""Clean and shape node or way XML element to Python dict""" node_attribs = {} #存放生成node的key和value,key作表头,value作内容
way_attribs = {} #存放生成way的key和value,key作表头,value作内容
way_nodes = [] #存放生成way标签下的nd子标签的值,[{...},{...}]
tags = [] #存放node和way下的tag子标签的值 ,[{...},{...},]# Handle secondary tags the same way for both node and way elements # YOUR CODE HERE
#先提取node字段
if element.tag == 'node':
#1.循环node_field表头,如果element中有key所对应的属性,则放入到node_attribs字典中
for key in NODE_FIELDS:
node_attribs[key] = element.attrib[key]
#2.循环子节点,获取tags元素的值
for child in element:
Node_Tags = {}
#匹配字母和冒号
colon = re.match(LOWER_COLON,child.attrib['k'])
#匹配异常字符
problem = re.match(PROBLEMCHARS,child.attrib['k'])
#异常字符直接跳过,进行下一次查找
if problem:
continue
#如果tag是包含字母和冒号<tag k="addr:housenumber" v="1412"/>需要解析成{'id': 12345, 'key': 'housenumber', 'value': '1412', 'type': 'addr'}
elif colon:
#从父节点获取id属性的值
Node_Tags['id'] = element.attrib['id']
#获取k="addr:housenumber"的值,以:拆分,第一个值为type的值
type_value = child.attrib['k'].split(':',1)[0]
Node_Tags['type'] = type_value
#获取k="addr:housenumber"的值,以:拆分,第二个值为key的值
Node_Tags['key'] = child.attrib['k'].split(':',1)[1]
#获取v=1412的值,为value的值
Node_Tags['value'] = child.attrib['v']
#将处理后的数据加入到字典中
tags.append(Node_Tags)
#tag不包含冒号<tag k="building" v="yes"/>
else:
#从父节点获取id属性的值
Node_Tags['id'] = element.attrib['id']
#type的值是 regular
Node_Tags['type'] = 'regular'
#获取k=building的值,为key的值
Node_Tags['key'] = child.attrib['k']
#获取v=yes的值,为value的值
Node_Tags['value'] = child.attrib['v']
#将处理后的数据加入到字典中
tags.append(Node_Tags)
#返回node处理之后的结果
return {'node': node_attribs, 'node_tags': tags}
#在提取way字段
elif element.tag == 'way':
1.循环way_field表头,如果element中有key所对应的属性,则放入到way_attribs字典中
for key in WAY_FIELDS:
way_attribs[key] = element.attrib[key]
counter = 0 #计数,用于填充way下面nd子标签的position的值
#循环父节点下的子节点
for child in element:
Way_Nodes = {} #存放nd子标签
Way_Tags = {} #存放tag子标签
#处理nd子标签
if child.tag == 'nd':
#从父节点获取id属性的值
Way_Nodes['id'] = element.attrib['id']
#从自身的ref,来获取该属性的值
Way_Nodes['node_id'] = child.attrib['ref']
#获取position的值,每循环一次nd,counter + 1
Way_Nodes['position'] = counter
counter += 1
将处理后的nd子节点数据加入到字典中
way_nodes.append(Way_Nodes)
#处理tag子标签
elif child.tag == 'tag':
#同处理node下的tag子节点
colon = re.match(LOWER_COLON,child.attrib['k'])
problem = re.match(PROBLEMCHARS,child.attrib['k'])
if problem:
continue
elif colon:
Way_Tags['id'] = element.attrib['id']
type_value = child.attrib['k'].split(':',1)[0]
Way_Tags['key'] = child.attrib['k'].split(':',1)[1]
Way_Tags['type'] = type_value
Way_Tags['value'] = child.attrib['v']
tags.append(Way_Tags)
else:
Way_Tags['id'] = element.attrib['id']
Way_Tags['key'] = child.attrib['k']
Way_Tags['type'] = 'regular'
Way_Tags['value'] = child.attrib['v']
tags.append(Way_Tags)
return {'way': way_attribs, 'way_nodes': way_nodes, 'way_tags': tags} def get_element(osm_file, tags=('node', 'way', 'relation')):
"""Yield element if it is the right type of tag"""
"""如果是正确的类型时,返回标签中的tag"""
context = ET.iterparse(osm_file, events=('start', 'end'))
_, root = next(context)
for event, elem in context:
if event == 'end' and elem.tag in tags:
yield elem
root.clear() def validate_element(element, validator, schema=SCHEMA):
"""Raise ValidationError if element does not match schema"""
"""当和schema的数据格式不匹配时,抛出异常"""
if validator.validate(element, schema) is not True:
field, errors = next(validator.errors.iteritems())
message_string = "\nElement of type '{0}' has the following errors:\n{1}"
error_string = pprint.pformat(errors) raise Exception(message_string.format(field, error_string)) class UnicodeDictWriter(csv.DictWriter, object):
"""Extend csv.DictWriter to handle Unicode input"""
"""扩展csv下的DictWriter方法的去支持Unicode输入"""
def writerow(self, row):
super(UnicodeDictWriter, self).writerow({
k: (v.encode('utf-8') if isinstance(v, unicode) else v) for k, v in row.iteritems()
}) def writerows(self, rows):
for row in rows:
self.writerow(row) def process_map(file_in, validate):
"""Iteratively process each XML element and write to csv(s)"""
"""将处理好的xml文件写入到csv中"""
with codecs.open(NODES_PATH, 'w') as nodes_file, \
codecs.open(NODE_TAGS_PATH, 'w') as nodes_tags_file, \
codecs.open(WAYS_PATH, 'w') as ways_file, \
codecs.open(WAY_NODES_PATH, 'w') as way_nodes_file, \
codecs.open(WAY_TAGS_PATH, 'w') as way_tags_file: nodes_writer = UnicodeDictWriter(nodes_file, NODE_FIELDS)
node_tags_writer = UnicodeDictWriter(nodes_tags_file, NODE_TAGS_FIELDS)
ways_writer = UnicodeDictWriter(ways_file, WAY_FIELDS)
way_nodes_writer = UnicodeDictWriter(way_nodes_file, WAY_NODES_FIELDS)
way_tags_writer = UnicodeDictWriter(way_tags_file, WAY_TAGS_FIELDS) nodes_writer.writeheader()
node_tags_writer.writeheader()
ways_writer.writeheader()
way_nodes_writer.writeheader()
way_tags_writer.writeheader() validator = cerberus.Validator() for element in get_element(file_in, tags=('node', 'way')):
el = shape_element(element)
if el:
if validate is True:
validate_element(el, validator) if element.tag == 'node':
nodes_writer.writerow(el['node'])
node_tags_writer.writerows(el['node_tags'])
elif element.tag == 'way':
ways_writer.writerow(el['way'])
way_nodes_writer.writerows(el['way_nodes'])
way_tags_writer.writerows(el['way_tags'])

第二种方法

高阶解法

def shape_tag(el, tag): 
#tag标签返回的格式(el是父节点标签指的是node标签,tag是子节点指的是tag标签)
tag = {
'id' : el.attrib['id'],
'key' : tag.attrib['k'],
'value': tag.attrib['v'],
'type' : 'regular'
} if LOWER_COLON.match(tag['key']):
#如果tag的key中出现冒号<tag k="addr:housenumber" v="1412"/>,则根据:进行拆分,获取type和key
tag['type'], _, tag['key'] = tag['key'].partition(':')
return tag def shape_way_node(el, i, nd):
#way下的nd标签返回的格式(el是父节点标签指的是way标签,nd是子节点指的是nd标签)
return {
'id' : el.attrib['id'],
'node_id' : nd.attrib['ref'],
'position' : i
} def shape_element(element, node_attr_fields=NODE_FIELDS, way_attr_fields=WAY_FIELDS,
problem_chars=PROBLEMCHARS, default_tag_type='regular'):
"""Clean and shape node or way XML element to Python dict""" node_attribs = {}
way_attribs = {}
way_nodes = []
#直接获取所有的tag子标签
tags = [shape_tag(element, t) for t in element.iter('tag')] # Handle secondary tags the same way for both node and way elements # YOUR CODE HERE
if element.tag == 'node':
node_attribs = {f: element.attrib[f] for f in node_attr_fields}
return {'node': node_attribs, 'node_tags': tags}
elif element.tag == 'way':
way_attribs = {f: element.attrib[f] for f in way_attr_fields}
#获取way标签下nd标签的各个值
way_nodes = [shape_way_node(element, i, nd)
for i, nd
in enumerate(element.iter('nd'))]
return {'way': way_attribs, 'way_nodes': way_nodes, 'way_tags': tags}

6.数据清洗(准备数据库 MonogoDB版本)

处理数据并将数据形状变成我们之前提到的模型。输出应该是字典列表,如下所示

{
"id": "",
"type: "node",
"visible":"true",
"created": {
"version":"",
"changeset":"",
"timestamp":"2013-08-03T16:43:42Z",
"user":"linuxUser16",
"uid":""
},
"pos": [41.9757030, -87.6921867],
"address": {
"housenumber": "",
"postcode": "",
"street": "North Lincoln Ave"
},
"amenity": "restaurant",
"cuisine": "mexican",
"name": "La Cabana De Don Luis",
"phone": "1 (773)-271-5176"
}

要求:

1.node下的tag子标签处理如下

<tag k="addr:housenumber" v=""/>
<tag k="addr:street" v="North Lincoln Avenue"/>
<tag k="addr:street:name" v="Lincoln"/>
<tag k="addr:street:prefix" v="North"/>
<tag k="addr:street:type" v="Avenue"/>
<tag k="amenity" v="pharmacy"/> 应该改写为: {...
"address": {
"housenumber": 5158,
"street": "North Lincoln Avenue"
}
"amenity": "pharmacy",
...
}

2.way标签下的子标签的处理应该改为

<nd ref=""/>
<nd ref=""/>
应该改为
"node_refs": ["", ""]
lower = re.compile(r'^([a-z]|_)*$')
lower_colon = re.compile(r'^([a-z]|_)*:([a-z]|_)*$')
problemchars = re.compile(r'[=\+/&<>;\'"\?%#$@\,\. \t\r\n]') CREATED = [ "version", "changeset", "timestamp", "user", "uid"] def shape_element(element):
node = {}
if element.tag == "node" or element.tag == "way" :
# YOUR CODE HERE #1.获取非父子节点的key和value
node = {tag.attrib['k']:tag.attrib['v']
for tag in element.iter('tag')
if not tag.attrib['k'].startswith('addr:')
and not problemchars.search(tag.attrib['k'])}
#2.获取address节点的key和value
#例:<tag k="addr:street:name" v="Lincoln"/>
#1)将addr:后面的字符作为key,v的值作为value
#2)如果标签中的key值以addr:开头,且:的数量等于1
#3)且没有特殊字符的存在
node['address'] = {tag.attrib['k'][5:]: tag.attrib['v']
for tag in element.iter('tag')
if tag.attrib['k'].startswith('addr:')
and tag.attrib['k'].count(':') == 1
and not problemchars.search(tag.attrib['k'])}
#3.获取element节点的属性
     attr = element.attrib
node['id'] = attr['id'] #获取id
node['type'] = element.tag #获取类型type
node['visible'] = attr.get('visible') #获取visible      #4.获取created节点中的key和value
node['created'] = {c:attr[c] for c in CREATED}
#5.如果标签的类型是way,则从该标签获取ref的值封装到node_refs中,否则直接从node中获取lat,lon的值填充到pos中
if element.tag == 'way':
node['node_refs'] = [nd.attrib['ref'] for nd in element.iter('nd')]
else:
node['pos'] = [float(attr['lat']),float(attr['lon'])]
return node
else:
return None def process_map(file_in, pretty = False):
# You do not need to change this file
file_out = "{0}.json".format(file_in)
data = []
with codecs.open(file_out, "w") as fo:
for _, element in ET.iterparse(file_in):
el = shape_element(element)
if el:
data.append(el)
if pretty:
fo.write(json.dumps(el, indent=2)+"\n")
else:
fo.write(json.dumps(el) + "\n")
return data
def test():
#如果测试代码不出错,则结果正确
correct_first_elem = {
"id": "",
"visible": "true",
"type": "node",
"pos": [41.9730791, -87.6866303],
"created": {
"changeset": "",
"user": "bbmiller",
"version": "",
"uid": "",
"timestamp": "2012-03-28T18:31:23Z"
}
}
assert data[0] == correct_first_elem
assert data[-1]["address"] == {
"street": "West Lexington St.",
"housenumber": ""
}
assert data[-1]["node_refs"] == [ "", "", "", "",
"", "", ""] if __name__ == "__main__":
test()

OpenStreetMap数据清洗(SQL&MonogoDB版本)的更多相关文章

  1. 使用的 SQL Server 版本不支持数据类型“datetime2”.

    错误原因,在使用ado.net entity的时候,entity使用的数据库是sqlserver 2008, 但后来实际使用中使用的数据库是sqlserver 2005, 使用的 SQL Server ...

  2. sql server版本、组件和管理工具

    以下信息由何问起收集,希望有帮助. SQL Server 版本 定义 Enterprise 作为高级版本, SQL Server Enterprise 版提供了全面的高端数据中心功能,性能极为快捷.虚 ...

  3. SQL SERVER版本补丁体系及升级

    首先了解几个定义: RTM : 表示 Release to Manufacturing ,这是产品的原始发布版本,当从光盘或 MSDN 下载的默认版本.不过现在下载 SQL Server 版本时,也有 ...

  4. ef SQL Server 版本不支持数据类型“datetime2”

    我遇到这个问题是在用数据库模型的时候.当时我电脑上是sql2008 通过vs2010建立了一个ADO.net数据库模型,之后在项目上线的时候,临时把数据库换成了sql2005,在添加新闻的时候出现了“ ...

  5. PIVOT 和 UNPIVOT 命令的SQL Server版本

    I:使用 PIVOT 和 UNPIVOT 命令的SQL Server版本要求 1.数据库的最低版本要求为 SQL Server 2005 或 更高 2.必须将数据库的兼容级别设置为 90 或 更高 3 ...

  6. C#检验IIS版本、SQL Server版本、SilverLight版本

    之前做一个小项目,使用C#检验这些软件的版本,到处找了一些代码,也能作用,记录一下,以防以后用到. 一.检验IIS版本 public static bool checkIIS(string destV ...

  7. sql server2005版本中,len函数计算了字符串末尾的空格

    sql server2005版本中,len函数计算了字符串末尾的空格的长度,以下是测试脚本: print @@version declare @v varchar(max) set @v = 'hp, ...

  8. PCB MS SQL SERVER版本管控工具source_safe_for_sql_server

    PCB由于业务关系复杂,业务触发一个事件时,可能需与数据库多个表进行关连处理才能拿到数据结果, 而表关连并不是简单的关连,实际是要进行大量数据筛选,逻辑判断,转换等过程...这个过程是复杂的 想一想, ...

  9. [转帖]sql server版本特性简介、版本介绍简介

    sql server版本特性简介.版本介绍简介 https://www.cnblogs.com/gered/p/10986240.html 目录 1.1.sql server的版本信息 1.2.版本重 ...

随机推荐

  1. 基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案

    基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案 最近在研究Java,涉及命令行编译,使用notepad++编辑器,然后使用javac编译: 之前的几个文件没有中文的内容,都没 ...

  2. [51nod1676]无向图同构

    如果一个无向图重标号后与另一个无向图完全一致(即对于任意两点,他们之间的边在两个图中都存在或都不存在),则称两个无向图同构. 给定两个n个点m条边的无向图,判定两个无向图是否同构.不超过20组数据,n ...

  3. HDU2973(威尔逊定理)

    YAPTCHA Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  4. in运算符(javascript)

    in的用法,如x in y: 1.如果第二个运算数为对象,则in运算符用来检测第一个运算数是否是第二个运算数的属性名.是,返回true,否则返回false. 例: var obj = {x:1,y:2 ...

  5. java常量池詳解

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  6. 【Jsp/Servlet】获取客户端使用的ip

    一般使用jsp的时候大多数时间都可以使用request.getRemoteAddr() 来获取ip,但是这个前提是未经过反向代理等操作的原始地址,所以,需要在反向代理等操作之后还要获取客户端的ip变得 ...

  7. 从CUMT校园导航出现的问题看CSS布局设计(一) CSS盒模型

    先说说做的这个校园导航系统值得一提的内容: 1. 二级菜单栏  .iframe内嵌窗口(样式设计.用hover做效果) 2. 高德地图API (自定义底图样式.弹跳点.信息窗体.线路导航) 3. DO ...

  8. 数据库复习总结(16)-case关键字(数据透视)

    case语法: 练习1:将性别的0.1显示为男.女 select * from StudentInfo --case:对结果集中的列进行判断 --例1:显示学生信息,性别以"男女" ...

  9. <button>与<input type="button">的区别

    一.定义和用法 <button> 标签定义的是一个按钮. 在 button 元素内部,可以放置文本或图像.这是<button>与使用 input 元素创建的按钮的不同之处. 二 ...

  10. 前端HTML介绍

    一.HTML简介 HTML定义: 超级文本标记语言是标准通用标记语言下的一个应用,也是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分.网页文件本身是一种文本文件,通过在文本文件中添加 ...