我有两个类似的代码需要解析,我不确定实现这个目的的最pythonic方法。
假设我有两个相似的“代码”
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
这两个代码以$$otherthing
结尾,并包含以-
首先,我想到使用functools.wrap
将一些常见逻辑与特定于每种代码类型的逻辑分开,如下所示:
from functools import wraps
def parse_secret(f):
@wraps(f)
def wrapper(code, *args):
_code = code.split('$$')[0]
return f(code, *_code.split('-'))
return wrapper
@parse_secret
def parse_code_1b(code, a, b, c):
a = a.split('|')[0]
return (a,b,c)
@parse_secret
def parse_code_2b(code, a, b):
b = b.split('|')[1]
return (a,b)
然而,这样做会使你应该将实际传递给parse_code_*
函数的参数混淆,例如。
parse_code_1b(secret_code_1)
parse_code_2b(secret_code_2)
因此,为了更容易理解函数的形式参数,我将逻辑更改为:
def _parse_secret(parse_func, code):
_code = code.split('$$')[0]
return parse_func(code, *_code.split('-'))
def _parse_code_1(code, a, b, c):
"""
a, b, and c are descriptive parameters that explain
the different components in the secret code
returns a tuple of the decoded parts
"""
a = a.split('|')[0]
return (a,b,c)
def _parse_code_2(code, a, b):
"""
a and b are descriptive parameters that explain
the different components in the secret code
returns a tuple of the decoded parts
"""
b = b.split('|')[1]
return (a,b)
def parse_code_1(code):
return _parse_secret(_parse_code_1, code)
def parse_code_2(code):
return _parse_secret(_parse_code_2, code)
现在更容易推断你传递给函数的内容:
parse_code_1(secret_code_1)
parse_code_2(secret_code_2)
然而,这段代码更加详细。
有更好的方法吗?面向对象的方法在这里会更有意义吗?
答案 0 :(得分:2)
功能方法更简洁,更有意义。
我们可以从pure functions中表达概念开始,这是最容易构成的形式。
剥离$$otherthing
并拆分值:
parse_secret = lambda code: code.split('$$')[0].split('-')
选择一个内在值:
take = lambda value, index: value.split('|')[index]
将其中一个值替换为其内部值:
parse_code = lambda values, p, q: \
[take(v, q) if p == i else v for (i, v) in enumerate(values)]
这两种类型的代码有3个不同之处:
我们可以通过描述这些差异来组成解析函数。拆分值保持打包状态,以便更容易编写。
compose = lambda length, p, q: \
lambda code: parse_code(parse_secret(code)[:length], p, q)
parse_code_1 = compose(3, 0, 0)
parse_code_2 = compose(2, 1, 1)
并使用组合函数:
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
results = [parse_code_1(secret_code_1), parse_code_2(secret_code_2)]
print(results)
答案 1 :(得分:1)
我相信这样的事情可行:
secret_codes = ['asdf|qwer-sdfg-wert$$otherthing', 'qwersdfg-qw|er$$otherthing']
def parse_code(code):
_code = code.split('$$')
if '-' in _code[0]:
return _parse_secrets(_code[1], *_code[0].split('-'))
return _parse_secrets(_code[0], *_code[1].split('-'))
def _parse_secrets(code, a, b, c=None):
"""
a, b, and c are descriptive parameters that explain
the different components in the secret code
returns a tuple of the decoded parts
"""
if c is not None:
return a.split('|')[0], b, c
return a, b.split('|')[1]
for secret_code in secret_codes:
print(parse_code(secret_code))
输出:
('asdf', 'sdfg', 'wert')
('qwersdfg', 'er')
我不确定您的秘密数据结构,但是如果您使用具有数据的元素位置的索引|在它中并拥有适当数量的秘密数据,你也可以做这样的事情并且可能有无限的(差不多)秘密数量:
def _parse_secrets(code, *data):
"""
data is descriptive parameters that explain
the different components in the secret code
returns a tuple of the decoded parts
"""
i = 0
decoded_secrets = []
for secret in data:
if '|' in secret:
decoded_secrets.append(secret.split('|')[i])
else:
decoded_secrets.append(secret)
i += 1
return tuple(decoded_secrets)
答案 2 :(得分:1)
我真的不确定你到底是什么意思。但我想到了你可能正在寻找的想法。
如何使用这样的简单函数:
def split_secret_code(code):
return [code] + code[:code.find("$$")].split("-")
而不仅仅是使用:
parse_code_1(*split_secret_code(secret_code_1))
答案 3 :(得分:1)
你嫁给了字符串解析吗?如果要使用值传递变量并且不需要变量名,则可以将它们“打包”为整数。
如果您正在使用加密技术,您可以制定一个长十六进制数字的字符,然后将其作为int传递“stop”字节(例如0000因为“0”实际上是48次尝试:chr(48)
)并且如果你嫁给了一个字符串我会建议一个较低的字符字节标识符,例如(1 - > aka try:chr(1)
)所以你可以扫描整数并将它移位8来获得8位掩码的字节(这看起来像(secret_code>>8)&0xf
。
哈希以类似的方式工作,因为可以解析一个带有 somename 和 somevalue , somename 和 somevalue 的变量作为整数然后与stop模块连接,然后在需要时检索。
让我举一个散列的例子
# lets say
a = 1
# of sort hashing would be
hash = ord('a')+(0b00<<8)+(1<<16)
#where a hashed would be 65633 in integer value on 64 bit computer
# and then you just need to find a 0b00 aka separator
如果你只想使用变量(名称无关紧要),那么你只需要散列变量值,这样解析后的值的大小要小得多(不是名称部分,不需要分隔符(0b00),你可以巧妙地使用分隔符将必要数据分成一倍(0b00)双倍(0b00,0b00 <8)等。
a = 1
hash = a<<8 #if you want to shift it 1 byte
但是如果你想要隐藏它并且你需要密码学示例,你可以执行上述方法然后加扰,移位(a-> b)或稍后将其转换为另一种类型。您只需要弄清楚您正在进行的操作的顺序。由于a-STOP-b-PASS-c不等于a-PASS-b-STOP-c。
您可以在此处找到按位运算符binary operators
但请记住,65是数字,65是一个字符,它只关注那些发送的字节,如果它们被发送到显卡它们是像素,如果它们被发送到audiocard,它们是声音,如果它们被送到数学处理他们是数字,作为程序员,我们的操场。
但如果这不能解决您的问题,您可以随时使用地图。
def mapProcces(proccesList,listToMap):
currentProcces = proccesList.pop(0)
listToMap = map( currentProcces, listToMap )
if proccesList != []:
return mapProcces( proccesList, listToMap )
else:
return list( listToMap )
然后你可以映射它:
mapProcces([str.lower,str.upper,str.title],"stackowerflow")
或者您可以简单地用空格替换每个明确的分隔符,然后分割空格。
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
separ = "|,-,$".split(",")
secret_code_1 = [x if x not in separ else " " for x in secret_code_1]# replaces separators with empty chars
secret_code_1 = "".join(secret_code_1) #coverts list to a string
secret_code_1 = secret_code_1.split(" ") #it splited them to list
secret_code_1 = filter(None,secret_code_1) # filter empty chars ''
first,second,third,fourth,other = secret_code_1
你有它,你的secret_code_1被拆分并分配给确定数量的变量。当然“”用作声明,你可以使用你想要的任何东西,如果你愿意,可以用“someseparator”替换每个分隔符,然后用“someseparator”分割。您还可以使用str.replace
功能使其更清晰。
我希望这会有所帮助
答案 4 :(得分:1)
我不确定你正在使用什么约束,但它看起来像:
直截了当的例子
这不是很难解决,而且你不需要花哨的包装器,所以我会放弃它们,因为它增加了阅读的复杂性。
def pre_parse(code):
dash_code, otherthing = code.split('$$')
return dash_code.split('-')
def parse_type_1(code):
dash_args = pre_parse(code)
dash_args[0], toss = dash_args[0].split('|')
return dash_args
def parse_type_2(code):
dash_args = pre_parse(code)
toss, dash_args[1] = dash_args[1].split('|')
return dash_args
# Example call
parse_type_1(secret_code_1)
尝试按照说明回答问题
您可以通过使用python的本机装饰器模式与*
结合使用这种方式提供参数,该模式将位置参数滚动/展开为元组,因此您无需确切知道它们的数量。
def dash_args(code):
dash_code, otherthing = code.split('$$')
return dash_code.split('-')
def pre_parse(f):
def wrapper(code):
# HERE is where the outer function, the wrapper,
# supplies arguments to the inner function.
return f(code, *dash_args(code))
return wrapper
@pre_parse
def parse_type_1(code, *args):
new_args = list(args)
new_args[0], toss = args[0].split('|')
return new_args
@pre_parse
def parse_type_2(code, *args):
new_args = list(args)
toss, new_args[1] = args[1].split('|')
return new_args
# Example call:
parse_type_1(secret_code_1)
更可扩展的示例
如果由于某种原因你需要支持这种解析的许多变体,你可以使用简单的OOP设置,比如
class BaseParser(object):
def get_dash_args(self, code):
dash_code, otherthing = code.split('$$')
return dash_code.split('-')
class PipeParser(BaseParser):
def __init__(self, arg_index, split_index):
self.arg_index = arg_index
self.split_index = split_index
def parse(self, code):
args = self.get_dash_args(code)
pipe_arg = args[self.arg_index]
args[self.arg_index] = pipe_arg.split('|')[self.split_index]
return args
# Example call
pipe_parser_1 = PipeParser(0, 0)
pipe_parser_1.parse(secret_code_1)
pipe_parser_2 = PipeParser(1, 1)
pipe_parser_2.parse(secret_code_2)
答案 5 :(得分:1)
我的建议尝试以下内容:
基本上,它将公共逻辑和特定逻辑分成不同的函数(您可以使用OOP执行相同操作)。问题在于它使用一个映射器变量,该变量包含根据每个代码的内容选择特定解析器的逻辑。在这里:
def parse_common(code):
"""
Provides common parsing logic.
"""
encoded_components = code.split('$$')[0].split('-')
return encoded_components
def parse_code_1(code, components):
"""
Specific parsing for type-1 codes.
"""
components[0] = components[0].split('|')[0] # decoding some type-1 component
return tuple([c for c in components])
def parse_code_2(code, components):
"""
Specific parsing for type-2 codes.
"""
components[1] = components[1].split('|')[1] # decoding some type-2 component
return tuple([c for c in components])
def parse_code_3(code, components):
"""
Specific parsing for type-3 codes.
"""
components[2] = components[2].split('||')[0] # decoding some type-3 component
return tuple([c for c in components])
# ... and so on, if more codes need to be added ...
# Maps specific parser, according to the number of components
CODE_PARSER_SELECTOR = [
(3, parse_code_1),
(2, parse_code_2),
(4, parse_code_3)
]
def parse_code(code):
# executes common parsing
components = parse_common(code)
# selects specific parser
parser_info = [s for s in CODE_PARSER_SELECTOR if len(components) == s[0]]
if parser_info is not None and len(parser_info) > 0:
parse_func = parser_info[0][1]
return parse_func(code, components)
else:
raise RuntimeError('No parser found for code: %s' % code)
secret_codes = [
'asdf|qwer-sdfg-wert$$otherthing', # type 1
'qwersdfg-qw|er$$otherthing', # type 2
'qwersdfg-hjkl-yui||poiuy-rtyu$$otherthing' # type 3
]
print [parse_code(c) for c in secret_codes]
答案 6 :(得分:0)
我认为您需要提供有关您正在尝试实现的内容的更多信息,以及明确的约束条件。例如,$$
可以出现多少次?会不会有|
dividor?那种事。
为了广泛地回答你的问题,一个优雅的pythonic方法是使用python的解包功能,结合split。例如
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
first_$$_part, last_$$_part = secret_code_1.split('$$')
通过使用这种技术,除了简单的if
块之外,您还应该能够编写一个优雅的解析器。
答案 7 :(得分:0)
如果我理解正确,你希望能够定义你的函数,就像传递解析的参数一样,但是想要将未解析的代码传递给函数。
您可以与您提供的第一个解决方案非常相似。
from functools import wraps
def parse_secret(f):
@wraps(f)
def wrapper(code):
args = code.split('$$')[0].split('-')
return f(*args)
return wrapper
@parse_secret
def parse_code_1(a, b, c):
a = a.split('|')[0]
return (a,b,c)
@parse_secret
def parse_code_2(a, b):
b = b.split('|')[1]
return (a,b)
对于示例中提到的密码,
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
print (parse_code_1(secret_code_1))
>> ('asdf', 'sdfg', 'wert')
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
print (parse_code_2(secret_code_2))
>> ('qwersdfg', 'er')
答案 8 :(得分:0)
我对你的问题一无所知,也不了解你的代码,但也许一个简单的方法是通过正则表达式来理解它?
import re
secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing'
secret_code_2 = 'qwersdfg-qw|er$$otherthing'
def parse_code(code):
regex = re.search('([\w-]+)\|([\w-]+)\$\$([\w]+)', code) # regular expression
return regex.group(3), regex.group(1).split("-"), regex.group(2).split("-")
otherthing, first_group, second_group = parse_code(secret_code_2)
print(otherthing) # otherthing, string
print(first_group) # first group, list
print(second_group) # second group, list
输出:
otherthing
['qwersdfg', 'qw']
['er']