搜索框增强
之前增强了右上角搜索框的搜索和跳转功能。下面会介绍一些可以让你的搜索比直接搜单词更准确的方法。
- 严格来说,这算是制造了一门小语言。考虑到用户主要是 OIer,学习能力强,我就没有封装一层用按钮、选项框等组件做的壳。(套一层壳也不复杂,欢迎有兴趣的同学来套壳)
基础格式
首先,搜索目前可以在题目、比赛、博客和用户中进行。
- 搜索字符串被分成若干个词。每个形如
abc
的词表示搜索所有完整包含abc
的内容。此处包含指题目、比赛和博客的标题中包含,或者用户的用户名中包含。例子如下:(✔ 表示会搜索到,✖ 表示不会搜索到)
搜索字符串 \ 标题或用户名 | abc | XabcX | a bc | adbc |
---|---|---|---|---|
abc | ✔ | ✔ | ✖ | ✖ |
- 当有多个词时,每个词的结果会被合并,即只需要包含至少一个词就会被搜索到(类似对条件进行或):
搜索字符串 \ 标题或用户名 | abc | XdefX | def-abc | a bc d ef | adbecf |
---|---|---|---|---|---|
abc def 或 def abc 或 abc abc def | ✔ | ✔ | ✔ | ✖ | ✖ |
- 很多常见的搜索这样就可以完成了。如果没有额外要求可以直接看最下方快速跳转的部分。
进阶语法
有几个控制字符,可以让以它们开头的词有特殊的含义。注意,如果一个词一这些字符开头,它就不会像一般的词那样匹配标题或者用户名。
以 #
开头的 ID 模式串
以 #
开头的词表示匹配搜索结果 ID 的模式串。除了开头的 #
以外,后面可以跟以下字符:
- 数字
0
-9
,匹配这个数字本身 #
或者?
,匹配任意一个数字(开头的#
不属于此类)*
,匹配任意 $0$ 个或更多数字
例子如下:
搜索字符串 \ ID | 123 | 1234 | 133 | 13 |
---|---|---|---|---|
#123 | ✔ | ✖ | ✖ | ✖ |
#1#3 或 #1?3 | ✔ | ✖ | ✔ | ✖ |
#*3 | ✔ | ✖ | ✔ | ✔ |
#1? #*4 或 #1# #*4 | ✖ | ✔ | ✖ | ✔ |
- 虽然同是
#
开头的词之间是“或”的关系,但是不同类别的词之间是“与”的关系。例如abc #1* #2* def
会匹配所有带有abc
或者def
,并且编号以 $1$ 或 $2$ 开头的内容。 - 允许
#
代替?
是为了减少切换输入法。输入法为中文时 Shift + 3 也可以输入#
。 - 搜索用户时
#
开头的词不会生效,因为用户没有编号。
以 @
开头的用户名模式串
以 @
开头的词可以更自由地匹配用户名,对与用户名有关的内容生效(博客作者、用户)。除了开头的 @
以外,后面可以跟以下字符:
?
,匹配任意一个字符*
,匹配任意 $0$ 个或更多字符- 其他字符,匹配这个字符本身
例子如下:
搜索字符串 \ 内容 | @Alan 的博客 Halting | @Alan 的博客 Machines | @Curry 的博客 Combinators | 用户 @Alonzo | 用户 @Neumann |
---|---|---|---|---|---|
@*an @*z? | ✔ | ✔ | ✖ | ✔ | ✖ |
@*n* m | ✖ | ✔ | ✖ | ✖ | ✔ |
- 同样,同一个类别之间是或的关系,而不同类别之间是与的关系。
- 普通单词在题目、比赛和博客中匹配标题,而在用户中匹配用户名。
以 +
开头的标签
以 +
开头的单词匹配题目和博客的标签。标签名称为除了开头的 +
之外的其余字符。如 +模板题
会匹配所有包含 模板题
标签的题目和博客。
- 同样,多个
+
开头的词可以表示包含这些标签中的任意一个。 +
开头的词不对没有标签的比赛和用户生效。
以 :
开头的类型路径
以 :
开头的单词划定搜索结果的类型,规则简述如下:
- 所有可以搜索的内容作为一个初始类型;
- 每个类型可以有若干种分类方式,每种分类方式将这个类型分成若干种子类型;
- 每个分类方式另外可以有一些简写,简写可以视作这种分类方式下的几个子类型的并;
- 另外,在一个分类方式中,每个子类型或者简写可以有一些简短的别名,别名和原来的名字可以混用,方便输入。
现在包含所有内容的初始类型有 $1$ 种分类方式,分为如下子类型:
-
:problems
(别名:problem
、:p
)表示题目。题目目前有 $1$ 种分类方式,分为如下子类型::accepted
(别名:a
)表示你 AC 过的题目:unaccepted
(别名:na
)表示你没有 AC 过的题目
-
:contests
(别名:contest
、:c
)表示比赛。比赛目前有 $1$ 种分类方式,分为如下子类型::upcoming
(别名:u
)表示未开始的比赛:running
(别名:r
)表示正在进行的比赛:finished
(别名:f
)表示已经结束的比赛
:unfinished
(别名:nf
)表示所有未结束的比赛,即:upcoming
或:running
-
:blogs
(别名:blog
、:b
)表示博客。博客目前有 $1$ 种分类方式,分为如下子类型::blogs
(别名:blog
、:b
)表示文档类型的(一般的)博客:slides
(别名:slide
、:s
)表示幻灯片类型的博客
-
:users
(别名:user
、:u
)表示用户。用户目前没有下属的分类方式。
-
:all
(别名::a
)表示所有类型,即:problems
或:contests
或:blogs
或:users
。
这样,所有类型和子类型构成了一棵类似树的结构(每个节点可以有若干组孩子),这棵树以初始类型为根,每个类型都是树上的一个点。用一条从根开始的路径可以表示搜索结果中要包含该路径走到的点(以及它的整棵子树,因为子树中的所有点都是它的子类型)表示的类型。如 :problems
(或 :p
等) 可以表示包含所有题目,:problems:accepted
(或 :problems:a
、:p:accepted
、:p:a
等)可以表示包含所有 AC 的题目,:c:f
表示包含所有结束的比赛。整条路径是一个词,不包含空格。
简写可以表示从一个点的一组孩子开始走的若干条路径(虽然现在的简写都只走了一步)。因为这些路径不太可能终结在子树中的同一个点上,所以简写只能处于上一段中所述路径的末端,如 :all
(或 :a
)表示包含所有内容,而 :contests:unfinished
(或 :c:nf
等)表示包含所有未结束的比赛。
同上,整个搜索字符串中可以出现多个 :
开头的词,它们表示的类型条件会被“或”,如 :c:nf :b:s :u
表示在未开始的比赛、幻灯片和用户中搜索。当然也可以 :p:a :p:na
或 :p:a :p :p:a
等来表示在所有题目中搜索。
另外,注意和其他类别的词一样,如果搜索字符串中没有任何以 :
开头的词,就可以在所有类型的内容中搜索;只要有以 :
开头的词,就只在它们表示的类型中搜索。
所以你其实需要知道的路径如下:
路径 | 表示的类型 |
---|---|
:p | 题目 |
:p:a | AC 的题目 |
:p:na | 未 AC 的题目 |
:c | 比赛 |
:c:u | 未开始的比赛 |
:c:r | 正在进行的比赛 |
:c:f | 已结束的比赛 |
:c:nf | 未结束的比赛 |
:b | 博客 |
:b:b | 文档博客 |
:b:s | 幻灯片 |
:u | 用户 |
以 \
开头的一般词
现在还没有表示“以 #
、@
、+
、:
开头的一般词的方式。所以,如果一个词以 \
开头,并且第二个字符是控制字符(#
、@
、+
、:
、\
),那么这个词表示忽略开始的 \
,从第二个字符开始的一般词。例如:
\#123
表示在标题和用户名中搜索 #123\\abc
表示在标题和用户名中搜索 \abc\^def
表示在标题和用户名中搜索 \^def
分词方式
上面的描述一直对“词”的概念含糊其辞,在这里解释这个概念。
- 基本的词之间以任意多的空白字符(空格、Tab)等分开;
- 如果有词(无论是任何类型)中间需要包含空白字符,则可以用半角双引号(原先打算支持其他引号,但似乎有些麻烦)将整个词括起来,如:
"a b "
表示一般词“a b ”;"+a b"
表示标签“a b”;"\+a b"
表示一般词“+a b”;
- 如果词没有被双引号括起来,中间出现的双引号不会作特殊处理,如搜索字符串
+a"b c"d
会被认为是标签 a"b 和一般词 c"d; - 如果要在被双引号括起来的词中表示双引号,可以用
\"
表示转义;因此,为了避免无法表示真正的连续的 \",\
可以转义\
,表示单个的 \,即"
和\
可以由\
转义;暂不支持其他字符转义,如:"\""
表示一般词“"”;"\\"
表示一般词“\”;"\\\""
表示一般词“\"”;"\"
或"\\\"
不被当作一个完整的词,因为最右侧双引号被转义,所以双引号未闭合;"\\\a"
或"\\\\a"
均表示“\a”,即一般词“\a”,因为"\\\a"
中第三个\
并没有参与转义;\\abc
表示“\abc”,即一般词“\abc”;\\+def
表示“+def”,即一般词“+def”;\\\+ghi
或\\\\+ghi
表示“\+ghi”,即一般词“+ghi”;\\\\\+jkl
或\\\\\\+jkl
表示“\+jkl”,即一般词“\+ghi”;- 注意:引号内的转义和开头的控制字符
\
是两重不同的转义,先进行引号内的转义(将\"
和\\
替换成 " 和 \),再考察开头字符是不是控制字符\
。 - 这里可以认为是一个设计失误;HELP WANTED。
简而言之,空格和双引号分词,双引号内允许用 \
转义 "
和 \
而不转义其他字符;转义过后可能会有开头的控制字符 \
进行影响。如果要在双引号里表示非控制字符开头的一般词,或者非 \
开头的特殊词,正常转义即可;如果要表示非 \
的控制字符开始的一般词,开头可以加上一个或两个 \
;如果要表示以 \
开头的一般词,正常转义之外需要额外加上两个 \
,它们转义后变成一个 \
作为控制字符。
快速跳转
除了进入搜索界面之外,顶部右侧的搜索框还承担了快速跳转的功能,能快速跳转到题目、比赛、博客和用户。
现在支持的快速跳转格式如下:
#xxx
,如果xxx
是一个数字(即不包含#
、?
和*
),可以直接跳到对应编号的题目;@xxx
,如果满足xxx
模式的用户有且仅有一个人,可以直接跳转到对应用户的个人信息;:p #xxx
(或等价的:problems #xxx
、:problem #xxx
,下同)或#xxx :p
,如果xxx
是一个数字,可以直接跳转到对应编号的题目;:c #xxx
或#xxx :c
,跳转到对应比赛,同上;:b #xxx
或#xxx :b
,跳转到对应博客,同上;:b @xxx
或@xxx :b
,如果满足xxx
模式的用户有且仅有一个人,可以直接跳转到对应用户的博客首页;:u @xxx
或@xxx :u
,如果满足xxx
模式的用户有且仅有一个人,可以直接跳转到对应用户的个人信息;
如果不能快速跳转,则会进入搜索页面。
另外,搜索框在导航条 Tab 顺序的第二位,第一位是首页;这个搜索框也可以当作浏览器的搜索引擎,前提是在首页进行过至少一次搜索或手动配置。
欢迎报告 bug,以及学习实现你想要的功能。
以上。