Маркиране на куп думи?

Опитвам се да подчертая куп думи - затова написах разширение за пигменти. По принцип работи, но все още не ме удовлетворява.

Ето една проста идея, която би трябвало да работи: маркирайте думите по подходящ начин и целия друг текст, който не съответства на тези думи - в текст. Но това затваря:

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

Пълният работещ Python пакет за разширение на pygments е тук. Можете да получите и

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

да го регистрира в пигменти. След това можете да го тествате с:

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

(коментарите не са наистина полезни за Hot Keys -- но ми трябват за 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 е основно само за проследяване на a) какво остава за анализ и b) кой тип токен търсим следващия - този пример винаги трябва да редува съвпадение на text токен и kwd токен. - person spiralx; 21.08.2012
comment
Мислите ли, че има място за коментари? Опитвам се да направя # comment char: Опитах: 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+ между \bs, но не и ако първото \b е последвано от някоя от ключовите думи)

2) Относно съответстващите коментари: Въз основа на документацията за пигментите, вашият израз (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 не е charclass. Какво е 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