我正在使用包含整数的大型列表,我想对它们进行一些模式匹配(比如查找某些序列)。正则表达式是最合适的,除了它们似乎总是只处理字符列表,a.k.a。字符串。是否有任何库(使用任何语言)可以处理任意类型的列表?
我知道我可以将整数列表转换为字符串,然后进行正常的正则表达式搜索,但这看起来有点浪费和不优雅。
修改
我的要求相当简单。不需要嵌套列表,不需要花哨的字符类。基本上我只对可能变得非常复杂的序列的出现感兴趣。 (例如"[abc]{3,}.([ab]?[^a]{4,7})"
等a
,b
,c
为整数的内容。这应该可以概括为可以检查相等性的任何类型。对于可枚举类型,您还可以使用"[a-z]"
之类的东西。
答案 0 :(得分:2)
正则表达式仅匹配字符串by definition。
当然,理论上你可以构造一个等价的语法,比如数字列表。对于偶数,\e
为新标记,奇数为\o
,方数为\s
,实数为\r
等,所以
[1, 2, 3, 4, 5, 6]
将匹配
^(\o\e)*$
或
[ln(3), math.pi, sqrt(-1)]
将匹配
^\R*$
等。听起来像一个有趣的项目,但也像一个非常困难的项目。如何扩展以处理任意列表,嵌套和所有,都超出了我的范围。
答案 1 :(得分:1)
一些正则表达式语法概括为泛型序列。此外,为了能够指定任何对象,字符串不是表达式本身的最佳媒介。
python中的“小”示例:
def choice(*items):
return ('choice',[value(item) for item in items])
def seq(*items):
return ('seq',[value(item) for item in items])
def repeat(min,max,lazy,item):
return ('repeat',min,max,lazy,value(item))
def value(item):
if not isinstance(item,tuple):
return ('value',item)
return item
def compile(pattern):
ret = []
key = pattern[0]
if key == 'value':
ret.append(('literal',pattern[1]))
elif key == 'seq':
for subpattern in pattern[1]:
ret.extend(compile(subpattern))
elif key == 'choice':
jumps = []
n = len(pattern[1])
for i,subpattern in enumerate(pattern[1]):
if i < n-1:
pos = len(ret)
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
jumps.append(len(ret))
ret.append('placeholder for jump')
ret[pos] = ('choice',len(ret)-pos)
else:
ret.extend(compile(subpattern))
for pos in jumps:
ret[pos] = ('jump', len(ret)-pos)
elif key == 'repeat':
min,max,lazy,subpattern = pattern[1:]
for _ in xrange(min):
ret.extend(compile(subpattern))
if max == -1:
if lazy:
pos = len(ret)
ret.append('placeholder for jump')
ret.extend(compile(subpattern))
ret[pos] = ('jump',len(ret)-pos)
ret.append(('choice',pos+1-len(ret)))
else:
pos = len(ret)
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
ret.append(('jump',pos-len(ret)))
ret[pos] = ('choice',len(ret)-pos)
elif max > min:
if lazy:
jumps = []
for _ in xrange(min,max):
ret.append(('choice',2))
jumps.append(len(ret))
ret.append('placeholder for jump')
ret.extend(compile(subpattern))
for pos in jumps:
ret[pos] = ('jump', len(ret)-pos)
else:
choices = []
for _ in xrange(min,max):
choices.append(len(ret))
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
ret.append(('drop,'))
for pos in choices:
ret[pos] = ('choice',len(ret)-pos)
return ret
def match(pattern,subject,start=0):
stack = []
pos = start
i = 0
while i < len(pattern):
instruction = pattern[i]
key = instruction[0]
if key == 'literal':
if pos < len(subject) and subject[pos] == instruction[1]:
i += 1
pos += 1
continue
elif key == 'jump':
i += instruction[1]
continue
elif key == 'choice':
stack.append((i+instruction[1],pos))
i += 1
continue
# fail
if not stack:
return None
i,pos = stack.pop()
return pos
def find(pattern,subject,start=0):
for pos1 in xrange(start,len(subject)+1):
pos2 = match(pattern,subject,pos1)
if pos2 is not None: return pos1,pos2
return None,None
def find_all(pattern,subject,start=0):
matches = []
pos1,pos2 = find(pattern,subject,start)
while pos1 is not None:
matches.append((pos1,pos2))
pos1,pos2 = find(pattern,subject,pos2)
return matches
# Timestamps: ([01][0-9]|2[0-3])[0-5][0-9]
pattern = compile(
seq(
choice(
seq(choice(0,1),choice(0,1,2,3,4,5,6,7,8,9)),
seq(2,choice(0,1,2,3)),
),
choice(0,1,2,3,4,5),
choice(0,1,2,3,4,5,6,7,8,9),
)
)
print find_all(pattern,[1,3,2,5,6,3,4,2,4,3,2,2,3,6,6,5,3,5,3,3,2,5,4,5])
# matches: (0,4): [1,3,2,5]; (10,14): [2,2,3,6]
有几点改进:
答案 2 :(得分:0)
如果你真的需要像正则表达式那样的免费语法,那么你必须按照Tim的回答中所描述的那样。 如果您只搜索固定数量的模式,那么最简单,最快捷的方法就是编写自己的搜索/过滤功能。
答案 3 :(得分:0)
横向思维:下载.Net Framework Source code,解除Regex源代码并使其适应整数而不是字符。
只是一个想法。
答案 4 :(得分:0)
嗯,Erlang已经内置了模式匹配(你的类型)。我在Ruby中做了类似的事情 - 有点可能不太好的hackery,请参阅http://radiospiel.org/0x16-its-a-bird
答案 5 :(得分:0)
从1.9版开始,Clojure在标准库中有clojure.spec
,可以做到这一点,甚至更多。例如,描述一个可能以一个偶数结尾的奇数序列:
(require '[clojure.spec.alpha :as s])
(s/def ::odds-then-maybe-even (s/cat :odds (s/+ odd?)
:even (s/? even?)))
然后要获得匹配的子序列,您将执行以下操作:
(s/conform ::odds-then-maybe-even [1 3 5 100])
;;=> {:odds [1 3 5], :even 100}
(s/conform ::odds-then-maybe-even [1])
;;=> {:odds [1]}
并找出为什么序列与您的定义不匹配的原因:
(s/explain ::odds-then-maybe-even [100])
;; In: [0] val: 100 fails spec: ::odds-then-maybe-even at: [:odds] predicate: odd?
上查看带有示例的完整文档
答案 6 :(得分:-2)
您可以尝试pamatcher,它是一个JavaScript库,可以为任何类型的项目(任何类型)概括正则表达式的概念。
&#34; [abc] {3,}。([ab]?[^ a] {4,7})&#34;模式匹配,其中a,b,c是整数:
var pamatcher = require('pamatcher');
var a = 10;
var b = 20;
var c = 30;
var matcher = pamatcher([
{ repeat:
{ or: [a, b, c] },
min: 3
},
() => true,
{ optional:
{ or: [a, b] }
},
{ repeat: (i) => i != a,
min: 4,
max: 7
}
]);
var input = [1, 4, 8, 44, 55];
var result = matcher.test(input);
if(result) {
console.log("Pattern matches!");
} else {
console.log("Pattern doesn't match.");
}
注意:我是这个图书馆的创建者。