Regex tự khớp [đã đóng]


15

Viết một regex không tầm thường phù hợp với chính nó.

Ví dụ, #.*$sẽ khớp một nhận xét bên ngoài một chuỗi trong python cho đến cuối dòng và cũng khớp chính nó trong cú pháp regl perl.

Quy tắc :

  • Các biểu thức chính quy phải làm một cái gì đó hữu ích hoặc thực tế.
  • Cho biết cú pháp regex nào bạn đang sử dụng (ví dụ: perl hoặc POSIX).
  • Người chiến thắng là câu trả lời tuân thủ bình chọn cao nhất.
  • Sáng tạo!

6
Có một câu hỏi trên SO cách đây một thời gian, liệu có một biểu thức nào phù hợp với các biểu thức hợp lệ không: stackoverflow.com/questions/172303/
Kẻ

5
Xác định không tầm thường. Ý tôi là, OK, Asẽ là tầm thường, nhưng bạn vẽ đường này ở đâu? Và bằng cách "tự khớp", bạn có nghĩa là nó chỉ có thể khớp chính nó, hay nó cũng được phép khớp với các chuỗi khác? Sẽ .đủ điều kiện?
Ông Lister

1
@padde mà thực sự không phải là một regex vì ngữ pháp mô tả biểu thức chính quy là không có ngữ cảnh.
FUZxxl

1
@FUZxxl vâng, điều đó đúng nhưng người ta vẫn có thể viết một biểu thức chính phù hợp với các biểu thức chính khác, nhưng không quan tâm đến tính hợp lệ của các biểu thức khớp.
Patrick Oscarity

1
@padde Chà, regex không hợp lệ là gì? Một regex không hợp lệ rõ ràng không phải là một regex. Vì vậy, về cơ bản bạn nói: "đúng, điều đó đúng nhưng người ta vẫn có thể viết một regex phù hợp với các regex khác, nhưng không quan tâm nếu regex phù hợp thực sự là một regex" (sic!)
FUZxxl

Câu trả lời:



11

PYTHON

Dưới đây là một trình tạo regex tự khớp. Bạn cung cấp hai danh sách, một danh sách chứa dữ liệu đào tạo mà regex phải khớp (ngoài việc khớp chính nó), danh sách còn lại chứa dữ liệu đào tạo mà regex KHÔNG nên khớp:

from random import choice, randrange
import re
from itertools import zip_longest, chain, islice
from operator import itemgetter

CHAR_SET = [chr(i) for i in range(128)] + [r"\\", r"\d", r"\D",
                                           r"\w", r"\W", r"\s",
                                           r"\S", r"?:", r"\1",
                                           r"\2", r"\A", r"\b",
                                           r"\B", r"\Z", r"\.",
                                           r"\[", r"\]", r"\(",
                                           r"\)", r"\{", r"\}",
                                           r"\+", r"\|", r"\?",
                                           r"\*"]

CHAR_SAMPLE = []
BREAKPOINT = re.compile(
    r"""
    \(.*?\)|
    \[.*?\]|
    \{.*?\}|
    \w+(?=[\(\[\{])?|
    \S+?|
    \.\*\??|
    \.\+\??|
    \.\?\??|
    \\.|
    .*?
    """,
    re.VERBOSE)

MATCH_BRACKETS = {'(': ')', '[': ']', '{': '}'}
CLOSE_BRACKETS = {')', ']', '}'}
REGEX_SEEDER = [
    r".*?",
    r"(?:.*?)",
    r"\w|\s",
    r"(?<.*?)",
    r"(?=.*?)",
    r"(?!.*?)",
    r"(?<=.*?)",
    r"(?<!.*?)",
    ]

LEN_LIMIT = 100

def distribute(distribution):
    global CHAR_SAMPLE
    for item in CHAR_SET:
        if item in distribution:
            CHAR_SAMPLE.extend([item] * distribution[item])
        else:
            CHAR_SAMPLE.append(item)

def rand_index(seq, stop=None):
    if stop is None:
        stop = len(seq)
    try:
        return randrange(0, stop)
    except ValueError:
        return 0

def rand_slice(seq):
    try:
        start = randrange(0, len(seq))
        stop = randrange(start, len(seq))
        return slice(start, stop)
    except ValueError:
        return slice(0,  0)


#Mutation Functions

def replace(seq):
    seq[rand_index(seq)] = choice(CHAR_SAMPLE)

def delete(seq):
    del seq[rand_index(seq)]

def insert(seq):
    seq.insert(rand_index(seq, len(seq) + 1), choice(CHAR_SAMPLE))

def duplicate(seq):
    source = rand_slice(seq)
    seq[source.stop: source.stop] = seq[source]

def swap(seq):
    if len(seq) < 2: return
    a = rand_index(seq, len(seq) - 1)
    seq[a], seq[a + 1] = seq[a + 1], seq[a]

dummy = lambda seq: None

MUTATE = (
    replace,
    delete,
    insert,
    duplicate,
    swap,
    dummy,
    dummy,
    )

def repair_brackets(seq):
    """Attempts to lower the percentage of invalid regexes by
    matching orphaned brackets"""

    p_stack, new_seq = [], []
    for item in seq:
        if item in MATCH_BRACKETS:
            p_stack.append(item)
        elif item in CLOSE_BRACKETS:
            while p_stack and MATCH_BRACKETS[p_stack[-1]] != item:
                new_seq.append(MATCH_BRACKETS[p_stack[-1]])
                p_stack.pop()
            if not p_stack:
                continue
            else:
                p_stack.pop()
        new_seq.append(item)
    while p_stack:
        new_seq.append(MATCH_BRACKETS[p_stack.pop()])
    return new_seq

def compress(seq):
    new_seq = [seq[0]]
    last_match = seq[0]
    repeat = 1
    for item in islice(seq, 1, len(seq)):
        if item == last_match:
            repeat += 1
        else:
            if repeat > 1:
                new_seq.extend(list("{{{0}}}".format(repeat)))
            new_seq.append(item)
            last_match = item
            repeat = 1
    else:
        if repeat > 1:
            new_seq.extend(list("{{{0}}}".format(repeat)))
    return new_seq


def mutate(seq):
    """Random in-place mutation of sequence"""
    if len(seq) > LEN_LIMIT:
        seq[:] = seq[:LEN_LIMIT]
    c = choice(MUTATE)
    c(seq)

def crossover(seqA, seqB):
    """Recombination of two sequences at optimal breakpoints
    along each regex strand"""

    bpA = [item.start() for item in BREAKPOINT.finditer(''.join(seqA))]
    bpB = [item.start() for item in BREAKPOINT.finditer(''.join(seqA))]
    slObjA = (slice(*item) for item in zip(bpA, bpA[1:]))
    slObjB = (slice(*item) for item in zip(bpB, bpB[1:]))
    slices = zip_longest(
        (seqA[item] for item in slObjA),
        (seqB[item] for item in slObjB),
        fillvalue=[]
        )
    recombinant = (choice(item) for item in slices)
    return list(chain.from_iterable(recombinant))

#Fitness testing

def match_percentage(match):
    """Calculates the percentage a text actually matched
    by a regular expression"""

    if match and match.endpos:
        return (match.end() - match.start()) / match.endpos
    else:
        return 0.001

def fitness_test(seq, pos_matches, neg_matches):
    """Scoring algorithm to determine regex fitness"""

    try:
        self_str = ''.join(seq)
        regex = re.compile(self_str)
    except (re.error, IndexError):
        seq[:] = repair_brackets(seq)
        try:
            self_str = ''.join(seq)
            regex = re.compile(self_str)
        except (re.error, IndexError):
            return 0.001

    pos_score = sum(match_percentage(regex.search(item))
                    for item in pos_matches) / len(pos_matches) / 3

    neg_score = (1 - sum(match_percentage(regex.search(item))
                    for item in neg_matches) / len(neg_matches)) / 3

    self_score = match_percentage(regex.search(self_str)) / 3

    return pos_score + self_score + neg_score

#Population Management

def generate_pop(pos_matches, neg_matches, pop_size):
    sources = (pos_matches, REGEX_SEEDER)
    return [crossover(
        choice(choice(sources)), choice(choice(sources))
        ) for i in range(pop_size)]

def glean_pop(population, cutoff, fit_test, ft_args=()):
    scores = (fit_test(bug, *ft_args) for bug in population)
    ranked = sorted(zip(population, scores), key=itemgetter(1), reverse=True)
    maxItem = ranked[0]
    new_pop = next(zip(*ranked))[:cutoff]
    return maxItem, new_pop

def repopulate(population, pop_size):
    cutoff = len(population)
    for i in range(pop_size // cutoff):
        population.extend([crossover(choice(population), choice(population))
                           for i in range(cutoff)])
    population.extend([population[i][:] for i in range(pop_size - len(population))])

#Simulator
def simulate(pos_matches, neg_matches, pop_size=50, cutoff=10, threshold=1.0):
    population = generate_pop(pos_matches, neg_matches, pop_size)
    while True:
        for bug in population:
            mutate(bug)

        #Scoring step
        max_item, population = glean_pop(
            population,
            cutoff,
            fitness_test,
            (pos_matches, neg_matches)
            )

        #Exit condition:
        max_regex, max_score = max_item
        if max_score >= threshold:
            return max_score, max_regex
        """
        print(max_score, ''.join(max_regex))
        input("next?")"""

        #Repopulation Step:
        population = list(population)
        repopulate(population, pop_size)

1
Đây có phải là Python không?
Griffin

1
@JoelCornett Viết simulatechức năng của riêng tôi là một phần của việc sử dụng? simulateHàm của bạn không sử dụng đối số # 2.
Casey Kuball

1
@Darthfett: Không, đó là một ví dụ về cách bạn sẽ gọi hàm. Tôi đã sử dụng các tên biến mô tả nội dung (giả thuyết) của chúng. Lỗi của tôi về tham số 2, đó là một lỗi đánh máy. no_matchđược cho là đổi tên no_match_list. Đã chỉnh sửa
Joel Cornett

1
Tại sao bạn gọi population = generate_pop(pos_matches, neg_matches, pop_size), nhưng generate_pophàm không bao giờ sử dụng neg_matchestham số? Ngoài ra, bạn có thể vui lòng bao gồm một ví dụ về cách gọi hàm không? Tôi có thể gọi nó như thế simulate(["Hello","World","world"], ["woah","bad","dont match"])nào?
mbomb007

1
Này, đã được vài năm kể từ khi tôi viết bài này. Chỉ cần đọc qua mã mà không cần kiểm tra, có vẻ như là có, bạn có thể gọi simulate()hàm như bạn mô tả. Và đúng, bạn đã đúng: Tôi không sử dụng dữ liệu tiêu cực để tạo dân số ban đầu.
Joel Cornett

5

JavaScript biểu thức chính quy phù hợp với những thứ như nó.

/^\/\^\\\/\\\^[\\\[\]\/\^\${},\dd]{34}$/

Bạn có thể kiểm tra nó như vậy:

(function test() {
    var re =/^\/\^\\\/\\\^[\\\[\]\/\^\${},\dd]{34}$/;
    var m  =/=([^;]+)/.exec(test)[1];
    return re.exec(m);
})();

1
"Những thứ như nó" là gì? Đây là thực tế hay hữu ích trong bất kỳ cách nào?
Casey Kuball

2
@Darthfett: Nó khớp với các biểu thức chính quy tương tự cố gắng khớp chính chúng và biểu thức chính quy này. Không, nó không thực tế hoặc hữu ích theo bất kỳ cách nào, nhưng chỉ có thể thực tế hoặc hữu ích, nhưng cũng thú vị, biểu thức chính quy phù hợp với chính nó là một biểu thức chính quy để khớp với các biểu thức thông thường. Mà đã được thực hiện.
Ry-
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.