Выделить кучу слов?

Я пытаюсь выделить кучу слов, поэтому я написал расширение pygments. В принципе это работает, но все еще не к моему удовлетворению.

Вот простая идея, которая должна сработать: выделяйте слова соответствующим образом, а весь остальной текст, не соответствующий этим словам, — в тексте. Но это зависает:

from pygments.lexer import RegexLexer
from pygments.token import *

class HotKeyPoetry(RegexLexer):
    name = 'HotKeyPoetry'
    aliases = ['HotKeyPoetry']
    filenames = ['*.hkp']

    tokens = {
        'root': [

            (r'\bAlt\b', Generic.Traceback),
            (r'\bShft\b', Name.Variable),
            (r'\bSpc\b', Operator),
            (r'\bCtrl\b', Keyword.Type),
            (r'\bRet\b', Name.Label),
            (r'\bBkSpc\b', Generic.Inserted),
            (r'\bTab\b', Keyword.Type),
            (r'\bCpsLk\b', String.Char),
            (r'\bNmLk\b', Generic.Output),
            (r'\bScrlLk\b', String.Double),
            (r'\bPgUp\b', Name.Attribute),
            (r'\bPgDwn\b', Name.Builtin),
            (r'\bHome\b', Number.Oct),
            (r'\bEnd\b', Name.Constant),
            (r'\bDel\b', Name.Decorator),
            (r'\bIns\b', Number.Integer.Long),
            (r'\bWin\b', Name.Builtin.Pseudo),
            (r'\bF1?[1-9]\b', Name.Function),

            (r'(?!\b(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|Home|End|Del|Ins|Win|F5)\b)', Text),

        ]
    }

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

Изменить 1

So

r"(.+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|P‌​gDwn|‌​Home|End|Del|Ins|Win|F[12]?[1-9])\b))"

Исключающее регулярное выражение, которое я искал.

Теперь я пытаюсь сделать # символом комментария, чтобы все после него (внутри строки) было комментарием: я пробовал:

r"(.+?)(?:$|#.*$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|P‌​gDwn|‌​Home|End|Del|Ins|Win|F[12]?[1-9])\b))"

а также

r"([^#]+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgD‌​wn|‌​Home|End|Del|Ins|Win|F[12]?[1-9])\b))"

с последующим

 (r'#.*$', Comment),

Я также попытался добавить второе состояние:

'comment': [ 
      (r'#.*$', Comment),
],

-- но ничего не работает.

Редактировать 2

Полный рабочий пакет расширения pygments для Python находится здесь. Вы можете получить и

python setup.py build
python setup.py install --user

это зарегистрировать его в pygments. Затем вы можете протестировать его с помощью:

pygmentize -f html -O full -o test.html test.hkp

или укажите язык:

pygmentize -f html -O full -l HotKeyPoetry -o test.html test.hkp

Вот пример test.hkp:

Ctrl-Alt-{Home/End} ⇒ {beginning/end}-of-visual-line
Ctrl-Alt-{b/↓/↑} ⇒ {set/goto next/goto previous} bookmark # I have it in okular and emacs
Alt-{o/O} ⇒ switch-to-buffer{/-other-window}
Ctrl-{o/O} ⇒ find-file{/-other-window}
Ctrl-x o ⇒ ergo-undo-close-buffer # it uses ergoemacs' recently-closed-buffers
Ctrl-Alt-O ⇒ find-alternate-file

(комментарии не очень полезны для горячих клавиш, но они мне нужны для PyMOL ).


person Adobe    schedule 16.08.2012    source источник
comment
Должен ли регулярное выражение соответствовать хотя бы одному символу? Возможно, проблема в том, что последнее регулярное выражение соответствует пустой строке, поэтому никакие символы не «используются» и никогда не продвигаются вперед.   -  person MRAB    schedule 16.08.2012
comment
Может быть, вы правы. На самом деле я думал, что последнее регулярное выражение должно совпадать с указанными словами ( | ). Я проверю, это соответствует пустой строке.   -  person Adobe    schedule 16.08.2012
comment
На самом деле я имел в виду, что, поскольку (?!...) является отрицательным опережением, он никогда не будет потреблять никаких символов.   -  person MRAB    schedule 16.08.2012
comment
Относительно редактирования: ваше правило подстановочных знаков, вероятно, запускается перед правилом комментариев. Смотрите мой обновленный ответ.   -  person alexis    schedule 22.10.2012


Ответы (2)


Да, последнее регулярное выражение на самом деле не соответствует ни одному символу. Я пробовал этот код:

import re

regexes = {
  "text": re.compile(r"(.+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|Home|End|Del|Ins|Win|F1?[1-9])\b))"),
  "kwd": re.compile(r"(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|Home|End|Del|Ins|Win|F1?[1-9])\b")
}

def tokenise(state):
  while state["src"]:
    state["tok"] = "text" if state["tok"] == "kwd" else "kwd"
    #print "mode: {0:20} {1!r}".format(state["tok"].capitalize(), state["src"])

    m = regexes[state["tok"]].match(state["src"])
    if m:
      match = m.group(0)
      state["src"] = state["src"][m.end():]
      #print "  TOKEN({0}, {1!r})".format(state["tok"], match)
      yield "TOKEN({0}, {1!r})".format(state["tok"], match)


state = {
  "src": "A thing that, Tab, is AltCps or 'Win'. F8 is good, as is: F13.",
  "tok": "text"
}
print repr(state["src"])
print "\n".join(list(tokenise(state)))
print

state = {
  "src": "Alt thing that, Tab, is AltCps or 'Win'. F8 is good, as is: F13.",
  "tok": "text"
}
print repr(state["src"])
print "\n".join(list(tokenise(state)))
print

state = {
  "src": "Alt thing that, Tab, is AltCps or 'Win'. F8 is good, as is: F11",
  "tok": "text"
}
print repr(state["src"])
print "\n".join(list(tokenise(state)))
print

И это работает для случаев, которые я тестировал, регулярное выражение текста хорошо выглядит в вашем коде :)

person spiralx    schedule 16.08.2012
comment
Вау!.. r"(.+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|Home|End|Del|Ins|Win|F[12]?[1-9])\b))" работает. Я вижу, Вы хорошо разбираетесь в пигментах (я мог читать документы, но вполне мог понять, что означает state. Но я понял, что в пигментах нужно много всего текста). - person Adobe; 17.08.2012
comment
state в основном просто для отслеживания а) того, что осталось разобрать и б) какой тип токена мы ищем дальше - этот пример всегда должен чередоваться между сопоставлением токена text и токена kwd. - person spiralx; 21.08.2012
comment
Как вы думаете, есть место для комментариев? Я пытаюсь сделать # символ комментария: я пробовал: r"(.+?)(?:$|#.*$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|‌​Home|End|Del|Ins|Win|F[12]?[1-9])\b))" и r"([^#]+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|‌​Home|End|Del|Ins|Win|F[12]?[1-9])\b))", а затем (r'#.*$', Comment),, я также пытался добавить второе состояние: 'comment': [ (r'#.*$', Comment), ], -- но ничего не работает. - person Adobe; 15.10.2012

1) Вы неправильно понимаете, как работает (?!: он не соответствует тексту. Ваш последний RE (в исходном блоке кода) соответствует позиции, за которой не следует ни одно из перечисленных вами слов. Но он соответствует нулю символов текста, поэтому раскрашивать нечего, и вы не продвигаетесь вперед.

На самом деле вы имели в виду следующее: \b(?!(?:Alt|Shft|etc)\b)\w+\b. (Находит любое слово \w+ между \b, но не в том случае, если за первым \b следует любое из ключевых слов)

2) О сопоставлении комментариев. Судя по документации pygments, ваше выражение (r'#.*$', Comment) должно работать. Или, в стиле, использованном в примерах:

(r'#.*\n', Comment),

3) Вам нужно только одно состояние, поэтому добавьте правило комментариев к корневому состоянию. Несколько состояний предназначены для случаев, когда у вас разный синтаксис в разных местах, например. если вы смешали html и PHP или хотите выделить SQL внутри строки python.

4) Ваши правила должны соответствовать всем введенным вами данным. Правила проверяются по порядку, пока одно из них не сработает, поэтому вместо того, чтобы пытаться написать правило, которое не соответствует ключевым словам, вы можете поместить этот подстановочный знак в качестве последнего правила:

(r'(?s).', Text),

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

person alexis    schedule 16.08.2012
comment
Вы правы (?! не соответствует тексту. \b(?!(?:Alt|Shft|etc)\b)\w+\b — это очень хорошее ремесло, но оно оставляет пробелы и пунктуацию непревзойденными. Изменение \w на . ломает дело. В любом случае, я несколько раз читал Ваш ответ, читал о незахвате (:? и благодарю Вас за ответ. - person Adobe; 17.08.2012
comment
Да, конечно, он не включает пробелы и знаки препинания, поскольку весь ваш код основан на токенах. Поскольку у вас есть программа, которая вам нравится в другом ответе, я не буду спрашивать, что именно вы хотели сопоставить. - person alexis; 19.08.2012
comment
Но что означает r'(?s).'? s не является классом символов. Что здесь s? - person Adobe; 23.10.2012
comment
Посмотри, парень, посмотри. Это заставляет точку совпадать с новой строкой вместе с другими символами. - person alexis; 23.10.2012
comment
Ой. Хорошо, тогда. Хотя я где-то видел, что у пигментов по умолчанию re.DOTALL. Но я не уверен. - person Adobe; 23.10.2012
comment
Не совсем так, согласно этому по умолчанию включено re.MULTILINE, что влияет на ^ и $. Я тоже всегда их путаю. - person alexis; 24.10.2012