突出一堆单词?
Posted
技术标签:
【中文标题】突出一堆单词?【英文标题】:Highlight a bunch of words? 【发布时间】:2012-08-16 15:00:40 【问题描述】:我试图突出显示一堆单词 - 所以我写了一个 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
所以
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"([^#]+?)(?:$|\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),
],
--但没有任何效果。
编辑 2
完整的工作pygments扩展python包是here。你可以得到和
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
(cmets 对于热键并不是很有用——但我需要它们用于PyMOL)。
【问题讨论】:
正则表达式是否必须至少匹配一个字符?也许问题是最后一个正则表达式匹配一个空字符串,所以没有字符被“消耗”,它永远不会前进。 也许你是对的。实际上我认为 - 最后一个正则表达式必须匹配 ( | ) 指定的单词。我会检查它是否匹配空字符串。 我的真正意思是,由于(?!...)
是一个负前瞻,它永远不会消耗任何字符。
重新编辑:您的通配符规则可能在评论规则之前运行。请参阅我的更新答案。
【参考方案1】:
1) 您误解了(?!
的工作原理:它与文本不匹配。您的最后一个 RE(在原始代码块中)匹配的 位置 后面没有您列出的任何单词。但它匹配文本的零个字符,所以没有任何颜色可以让你继续前进。
您真正的意思是:\b(?!(?:Alt|Shft|etc)\b)\w+\b
。 (匹配\b
s 之间的任何单词\w+
,但如果第一个\b
后跟任何关键字,则不匹配)
2) 关于匹配 cmets: 根据 pygments 文档,您的表达式 (r'#.*$', Comment)
应该可以工作。或者,在示例中使用的样式中:
(r'#.*\n', Comment),
3) 你只需要一个状态,所以将注释规则添加到根状态。当你在不同的地方有不同的语法时,多个状态是适用的,例如如果您混合使用 html 和 php,或者如果您想突出显示 Python 字符串中的 SQL。
4) 您的规则需要匹配输入中的所有内容。规则会按顺序尝试,直到一个有效,所以不要尝试编写与关键字不匹配的规则,您可以将此通配符作为 last 规则:
(r'(?s).', Text),
它会一次推进一个角色,直到你得到其他规则可以匹配的东西。重复:删除匹配非关键字的长规则,并改用上述规则。
【讨论】:
您说得对,(?!
与文本不匹配。 \b(?!(?:Alt|Shft|etc)\b)\w+\b
是一个非常好的手艺——但它留下了无与伦比的空白和标点符号。将 \w
更改为 .
会破坏事情。任何方式我都读过你多次回答,读过关于非捕获(:?
,我感谢你的回答。
是的,当然它会省略空格和标点符号,因为您的所有代码都是基于令牌的。既然你在另一个答案中有一个你喜欢的程序,我不会问你到底想匹配什么。
但是r'(?s).'
是什么意思? s
不是字符类。 s
这里是什么?
查一下,伙计,look it up. 它使点匹配换行符和其他字符。
哦。好吧。我虽然在某处看到 pygments 默认有re.DOTALL
。但我不确定。【参考方案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
它适用于我测试的案例,文本正则表达式在您的代码中看起来不错:)
【讨论】:
哇!..r"(.+?)(?:$|\b(?=(Alt|Shft|Spc|Ctrl|Ret|BkSpc|Tab|CpsLk|NmLk|ScrlLk|PgUp|PgDwn|Home|End|Del|Ins|Win|F[12]?[1-9])\b))"
有效。我知道你擅长 pygments(我可以阅读文档,但可以完全了解 state
的含义。但我知道在 pygments 中,所有的文本都很多)。
state
基本上只是为了跟踪 a) 剩下要解析的内容和 b) 我们接下来要查找的令牌类型 - 此示例应始终在匹配 text
令牌和kwd
令牌。
你认为有空间给 cmets 吗?我正在尝试制作#
评论字符:我尝试过: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), ],
——但没有任何效果。
以上是关于突出一堆单词?的主要内容,如果未能解决你的问题,请参考以下文章