Python 3.x 从python中表示为字符串的配置单元结构数据类型中提取列
在我的python程序中,我需要编写一个函数,以hive数据类型作为输入,并返回数据类型是否有效 配置单元中支持的基本数据类型如下:Python 3.x 从python中表示为字符串的配置单元结构数据类型中提取列,python-3.x,regex,validation,parsing,re,Python 3.x,Regex,Validation,Parsing,Re,在我的python程序中,我需要编写一个函数,以hive数据类型作为输入,并返回数据类型是否有效 配置单元中支持的基本数据类型如下: supported_data_types: Set = {'void', 'boolean', 'tinyint', 'smallint', 'int', 'bigint', 'float', 'double', 'decimal', 'string', 'varchar', 'timestamp
supported_data_types: Set = {'void', 'boolean', 'tinyint', 'smallint', 'int', 'bigint', 'float', 'double',
'decimal', 'string', 'varchar', 'timestamp', 'date', 'binary'}
配置单元支持的复杂数据类型包括:
arrays: array<data_type>
maps: map<primitive_type, data_type>
structs: struct<col_name : data_type [comment col_comment], ...>
union: union<data_type, data_type, ...>
我还设法验证数组并将数据类型映射到任何嵌套级别。我注意到,对于数组,任何有效类型都有语法:array
。因此,如果我有一个类型数组
,我会递归地验证数据类型
。对于map,它的键始终是基元数据类型,因此,也可以递归地验证map数据类型。我使用以下函数递归验证数据类型
def-validate\u数据类型(\u-type:str)->bool:
_类型=_type.strip()
如果配置单元中的类型支持数据类型:
返回真值
#数组类型有语法:Array,其中data\u type是任何有效的data\u类型
如果_type.startswith(“数组”表示数据类型“数组”表示数据类型“映射”这里的任务是查找所有出现的逗号和冒号,这些逗号和冒号的数量与其左侧的
相同。虽然正则表达式确实有一些奇特的功能,例如在搜索时存储变量的能力,但我认为这个问题超出了它们的范围egex只对简单的模式匹配有用,比如识别URL。它很容易让人忘乎所以,想在任何地方应用正则表达式,但这通常会导致代码无法读取
这里最简单的解决方案是简单的ol'迭代。要实现提取列
函数,您需要一个拆分
函数,该函数忽略嵌套在
中的分隔符:
def first_索引(target:str,string:str)->int:
#查找`string`中第一个顶级出现的`target`的索引`
深度=0
对于范围内的i(len(string)):
如果字符串[i]=='>':
深度-=1
如果字符串[i]==目标且深度==0:
返回i
如果字符串[i]='
,您将从堆栈中弹出。这可以在字符串的一次扫描中完成。但比上述代码复杂得多
另外,一般建议:尝试返回False
而不是使用assert
。这样,当输入无效字符串时,您就不必担心代码崩溃
祝项目顺利!我明白你的意思。所以社区真的很棒。感谢你为解决这个问题所做的努力。
@abstractmethod
def extract_columns(dt: str) -> List[Tuple[str, str]]:
pass
dt = "struct<col_1: int, col_2 : struct<nested_col_1 : int, nested_col_2 : str>>"
extract_columns(dt)
>> [('col_1','int'), ('col_2', 'struct<nested_col_1 : int, nested_col_2 : str>')]
def first_index(target: str, string: str) -> int:
# Finds the index of the first top-level occurrence of `target` in `string`
depth = 0
for i in range(len(string)):
if string[i] == '>':
depth -= 1
if string[i] == target and depth == 0:
return i
if string[i] == '<':
depth += 1
# No matches were found
return len(string)
def top_level_split(string: str, separator: str) -> [str]:
# Splits `string` on every occurrence of `separator` that is not nested in a "<>"
split = []
while string != '':
index = first_index(target=separator, string=string)
split.append(string[:index])
string = string[index + 1 :]
return split
def is_valid_datatype(string: str) -> bool:
if is_valid_primitive(string):
return True
# Find the opening carrot
left = first_index(target='<', string=string)
# Find the closing carrot
right = first_index(target='>', string=string)
if left > right or right == len(string):
return False
# Make sure there isn't anything to the right of `right`
if string[right + 1 : ].strip() != '':
return False
# The name of the data type, e.g. "array"
type_name = string[ : left].strip()
# The substring between the carrots
contents = string[left + 1 : right]
if type_name == 'array':
return is_valid_datatype(contents)
if type_name == 'map':
# We don't need `top_level_split` here because the first type is always primitive
split = contents.split(',', 1)
return len(split) == 2 and is_valid_primitive(split[0]) and is_valid_datatype(split[1])
if type_name == 'struct':
# Get each column by splitting on top-level commas
for column in top_level_split(string=contents, separator=','):
# We don't need `top_level_split` here because the first type is a column name
split = column.split(':', 1)
if not (len(split) == 2 and is_valid_colname(split[0]) and is_valid_datatype(split[1])):
return False
# All columns were valid!
return True
if type_name == 'union':
for entry in top_level_split(string=contents, separator=','):
if not is_valid_datatype(entry):
return False
# All entries were valid!
return True
# The type name is not recognized
return False