搜索功能的更新

2019-05-08 01:28:57 By TRCYX

搜索框增强

之前增强了右上角搜索框的搜索和跳转功能。下面会介绍一些可以让你的搜索比直接搜单词更准确的方法。

  • 严格来说,这算是制造了一门小语言。考虑到用户主要是 OIer,学习能力强,我就没有封装一层用按钮、选项框等组件做的壳。(套一层壳也不复杂,欢迎有兴趣的同学来套壳)

太长不看版


基础格式

首先,搜索目前可以在题目、比赛、博客和用户中进行。

  • 搜索字符串被分成若干个词。每个形如 abc 的词表示搜索所有完整包含 abc 的内容。此处包含指题目、比赛和博客的标题中包含,或者用户的用户名中包含。例子如下:(✔ 表示会搜索到,✖ 表示不会搜索到)
搜索字符串 \ 标题或用户名abcXabcXa bcadbc
abc
  • 当有多个词时,每个词的结果会被合并,即只需要包含至少一个词就会被搜索到(类似对条件进行或):
搜索字符串 \ 标题或用户名abcXdefXdef-abca bc d efadbecf
abc defdef abcabc abc def
  • 很多常见的搜索这样就可以完成了。如果没有额外要求可以直接看最下方快速跳转的部分。

进阶语法

有几个控制字符,可以让以它们开头的词有特殊的含义。注意,如果一个词一这些字符开头,它就不会像一般的词那样匹配标题或者用户名。

# 开头的 ID 模式串

# 开头的词表示匹配搜索结果 ID 的模式串。除了开头的 # 以外,后面可以跟以下字符:

  • 数字 0-9,匹配这个数字本身
  • # 或者 ?,匹配任意一个数字(开头的 # 不属于此类)
  • * ,匹配任意 $0$ 个或更多数字

例子如下:

搜索字符串 \ ID123123413313
#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. 所有可以搜索的内容作为一个初始类型;
  2. 每个类型可以有若干种分类方式,每种分类方式将这个类型分成若干种子类型
  3. 每个分类方式另外可以有一些简写,简写可以视作这种分类方式下的几个子类型的并;
  4. 另外,在一个分类方式中,每个子类型或者简写可以有一些简短的别名,别名和原来的名字可以混用,方便输入。

现在包含所有内容的初始类型有 $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:aAC 的题目
: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,以及学习实现你想要的功能。

以上。

评论

avatar
wlzhouzhuan
orz

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。