Как заменить некоторую часть текста на основе словаря шаблонов и подставить значения в python, используя re.sub? - PullRequest
2 голосов
/ 17 апреля 2020

У меня есть список префиксов, которые я хочу использовать для подстановки текста. Моя программа работает всякий раз, когда я заменяю весь сопоставленный текст на соответствующее значение, но не в том случае, если я хочу сохранить некоторую часть сопоставленного текста и заменить другие части с помощью группировки:

prefixes = {
            r"http://www.w3.org/2002/07/owl#([a-z]+)": r"owl:\1",
            r"http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+)": r"rdf:\1",
            r"http://www.w3.org/2000/01/rdf-schema#([a-z]+)": r"rdfs:\1",
            r"http://schema.org/": "schema",
            r"http://www.w3.org/2001/XMLSchema#([a-z]+)": r"xsd:\1",
            r"http://purl.org/linked-data/sdmx#([a-z]+)": r"sdmx:\1",
            r"http://www.w3.org/XML/1998/namespace": r"xml"
            }
# test = "http://www.w3.org/XML/1998/namespace" # works for this
test = "http://www.w3.org/2000/01/rdf-schema#a" # Does not work!

regex = re.compile("|".join(map(re.escape, prefixes.keys())))

test = regex.sub(lambda match:prefixes[match.group(0)], test)

Я хочу заменить тест на "rdfs: a", но это не работает таким образом. Как мне изменить код для работы в этом сценарии?

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Немного сложного, но "зачем беспокоиться о группах"? В любом случае ни одно из ваших регулярных выражений не совпадает с концом строки ($), поэтому единственное, что вы теряете здесь, это то, что все, что после # начинается с одного символа a-z:

import re

prefixes = {
    r"http://www.w3.org/2002/07/owl#": r"owl:",
    r"http://www.w3.org/1999/02/22-rdf-syntax-ns#": r"rdf:",
    r"http://www.w3.org/2000/01/rdf-schema#": r"rdfs:",
    r"http://schema.org/": "schema",
    r"http://www.w3.org/2001/XMLSchema#": r"xsd:",
    r"http://purl.org/linked-data/sdmx#": r"sdmx:",
    r"http://www.w3.org/XML/1998/namespace": r"xml"
}
regex = re.compile("|".join(map(re.escape, prefixes.keys())))


test1 = "http://www.w3.org/XML/1998/namespace"
test2 = "http://www.w3.org/2000/01/rdf-schema#a"

assert regex.sub(lambda match:prefixes[match.group(0)], test1) == "xml"
assert regex.sub(lambda match:prefixes[match.group(0)], test2) == "rdfs:a"
1 голос
/ 21 апреля 2020

То, что вы пытаетесь сделать, это очень сложно. И вам на самом деле не нужно использовать группы и обратные ссылки, чтобы просто заменить соответствующий текст другой строкой, как предполагает другой ответ.

Однако, если бы была какая-либо причина, почему простой подход не смог бы правильно определить строки, которые вы хотите заменить, и выражения, которые у вас есть в группах, важны для сопоставления, тогда приведенные ниже могут решить проблему для вас.

>>> prefixes = {
...     1:  (r"http://www.w3.org/2002/07/owl#([a-z]+)", r"owl:\2"),
...     3:  (r"http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+)", r"rdf:\4"),
...     5:  (r"http://www.w3.org/2000/01/rdf-schema#([a-z]+)", r"rdfs:\6"),
...     7:  (r"http://schema.org/", "schema"),
...     8:  (r"http://www.w3.org/2001/XMLSchema#([a-z]+)", r"xsd:\9"),
...     10: (r"http://purl.org/linked-data/sdmx#([a-z]+)", r"sdmx:\11"),
...     12: (r"http://www.w3.org/XML/1998/namespace", r"xml")
...     }
...
>>> test_1 = "http://www.w3.org/XML/1998/namespace"
>>> test_2 = "http://www.w3.org/2000/01/rdf-schema#a"
>>>
>>> expr = '(' + ')|('.join(p[0] for p in prefixes.values()) + ')'
>>> 
>>> regex = re.compile(expr)
>>> 
>>> regex.findall(test_2)
[('', '', '', '', 'http://www.w3.org/2000/01/rdf-schema#a', 'a', '', '', 
  '', '', '', '')]

>>> regex.sub(lambda m: m.expand(prefixes[m.lastindex][1]), test_2)
'rdfs:a'

>>> regex.sub(lambda m: m.expand(prefixes[m.lastindex][1]), test_1)
'xml'

>>> 

There!

То, что у вас было раньше, не было не работает, потому что результаты сопоставления были определены динамически и не совпадают ни с одним из ключей словаря, в которых есть выражения, которых у целевого текста не будет.

Итак, проблема в том, как связать группу выражений с группой замещающих строк, в которых есть обратные ссылки на группы в выражении.

Я воспользовался преимуществом структура списка групп объекта сопоставления для получения индекса совпадающего выражения. Если я сделаю каждое подвыражение в словаре группой, используя круглые скобки, то re.sub() создаст объект сопоставления с таким количеством элементов группы в нем для каждого совпадения (см. Строку с regex.findall() - он показывает, как выглядит список групп совпадений структурированный).

Соответствующее подвыражение представлено в списке сопоставляемых объектов в виде непустой строки в позиции заключенного в скобки подвыражения.

>>> expr = '(' + ')|('.join(p[0] for p in prefixes.values()) + ')'
>>> expr
'(http://www.w3.org/2002/07/owl#([a-z]+))| 
 (http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+))| 
 (http://www.w3.org/2000/01/rdf-schema#([a-z]+))|
 (http://schema.org/)| 
 (http://www.w3.org/2001/XMLSchema#([a-z]+))|
 (http://purl.org/linked-data/sdmx#([a-z]+))|
 (http://www.w3.org/XML/1998/namespace)'

>>> regex.findall(test_2)
[('', '', '', '', 'http://www.w3.org/2000/01/rdf-schema#a', 'a', '', '', 
  '', '', '', '')]

Поэтому я изменил данные prefixes структура, чтобы быть словарем с ключом в позиции, которая будет возвращена m.lastindex - это индекс соответствующего подвыражения в скобках.

Обратные ссылки необходимо было отрегулировать так, чтобы они соответствовали позициям в списке совпадений. Например, \1 работает только для поиска первой группы совпадений в результатах.

Другой особенностью объекта сопоставления, который я использовал, был метод m.expand(), который преобразует обратные ссылки в группы, на которые они ссылаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...