【问题标题】:How to search a Dictionary with the contents of a list如何使用列表的内容搜索字典
【发布时间】:2012-09-29 01:05:31
【问题描述】:

假设我有一个 todo 文件 (todo.txt),它看起来像这样:

  • 就 Foo 项目给 Tom 打电话
  • 完成 Bar 项目的总结并发送给 Thomas
  • 让 Susan 向我和 Tom 发送她对 Foo 项目的预测

我希望能够编写这些任务并让 Vim 将相应的类别附加到每一行(@ 代表人员,& 代表项目):

Tom(或 Thomas)应该生成 @Tom, 苏珊应该生成@Susan, Foo 应该生成 &Foo 和 Bar &Bar

因此结果应该是:

  • 就 Foo 项目联系 Tom @Tom &Foo
  • 完成 Bar 项目的总结并发送给 Thomas @Tom &Bar
  • 让 Susan 将她对 Foo 项目的预测发送给我和 Tom @Susan @Tom & Foo

我创建了一个字典:

let dictodo = {'Tom': "@Tom", 'Thomas': "@Tom", 'Susan': "@Susan", 'Foo': "&Foo", 'Bar': "&Bar",}

我怎样才能每次在这个特定文件中创建一个新任务并离开插入模式时有一个自动命令启动一个函数(:autocmd InsertLeave todo.txt :call Filltodo() ?)

1) 这将创建一个包含该行不同单词的列表:我想

let words = split(getline('.'), '\W\+')

2) 使用此列表浏览 dictodo Dictionary

3) 并将字典中对应的单词(2 的 result)附加到行尾?我想

call setline(line('.'), getline('.') . ' ' . result)

如果我对 1) 和 3) 的解决方案没有弄错,那么 2) 是缺少的部分(我尝试了 keyvar 但失败了)

【问题讨论】:

    标签: vim


    【解决方案1】:

    类似这个函数:

    function! AddCat(pairs)
      let lines = []
      for line in getline(1,'$')
        let pairs = copy(a:pairs)
        let words = split(line, '\W\+')
        let cats = []
        " Looks for a category for every word and add it only once.
        call map(words,
              \'has_key(pairs, v:val) && index(cats, pairs[v:val]) == -1'
              \ . '? add(cats, pairs[v:val])'
              \ . ': ""')
        " Add the categories if non-empty.
        call add(lines, join([line]+cats))
      endfor
      call setline(1, lines)
    endfunction
    
    Define your pairs:
    
    let dictodo = {'Tom': "@Tom", 'Thomas': "@Tom", 'Susan': "@Susan", 'Foo': "&Foo", 'Bar': "&Bar",}
    

    然后这样称呼它:

    :call AddCat(dictodo)
    

    注意: @ZyX 的回答比我的更容易理解,我什至将他的建议用于我的。自己去看看吧。

    【讨论】:

    • :非常感谢您的回答,它有效,而且可以一次性处理所有行。
    • 我会使用map(filter(, has_key), a:pairs[v:val])。您的最后一个变体最适合性能,但包括我在内的所有三个变量之间的差异可能微不足道,除非待办事项中有太多数据(dictodo 中的数据量不会产生影响,除非使用@romainl 答案)。我选择了一个循环,因为我使用 remove() 来处理重复的键,并且使用带有两个副作用的 map() 的三行函数对于新手 vimer 的答案来说有点神秘。
    • 我遇到了一个难题:如何删除重复的“标签”?如果我在字典中输入了“Tom”:“@work”和“Susan”:“@work”,如果我写了 Call Tom 和 Susan,@work 将出现两次..
    • @ZyX 我同意你的所有观点,但我没有改变我的答案,因为你已经提供了一个很好的答案,我只是将它们指向你的。
    • 顺便说一下,line . (empty(cats) ? '' : ' ' . join(cats, ' ')) == join([line]+cats)(空格是默认分隔符)。
    【解决方案2】:
    function! s:AppLine(pairs, line)
        let pairs=copy(a:pairs)
        let r=a:line
        for word in split(a:line, '\W\+')
            if has_key(pairs, word)
                let tag=remove(pairs, word)
                call filter(pairs, 'v:val isnot# tag')
                let r.=' '.tag
            endif
        endfor
        return r
    endfunction
    function! AddCat(pairs)
        return setline('.', s:AppLine(a:pairs, getline('.')))
    endfunction
    

    用法:

    %call AddCat(dictodo)
    

    【讨论】:

    • @romainl 非常感谢您的回答。我已经尝试过它们并选择批准 El Isra 的答案,因为它一次性处理了所有行(当然,我知道其他两个答案也可以修改为这样做)。我可以补充一点,我是一个真正的 vimscripter 新手(romainl 似乎有点夸大其词......),我无法在你的 - 非常技术性的 - 论点之间做出决定。感谢您的帮助。
    • @ThG 如果您像我建议的那样使用%call AddCat(dictodo)(注意百分号),或者与@romainl 答案相同,他们也会做同样的事情。如果您不想想一次性处理所有行,@Raimondi 的答案将被修改,我们的不是。
    • 当然,你是对的。太感谢了。我怎样才能给你正确的答案?
    • 嗯,发现我可以做到。再次感谢
    【解决方案3】:

    我认为你应该使用列表而不是字典。

    根据您在问题中提供的构建块,这个快速而幼稚的功能似乎可以满足您的需求。不过要小心:变量的范围不正确,它不会检查是否已经有一些标签。

    function! TidyTodo()
      let listodo = [['Tom','@Tom'],['Thomas','@Tom'],['Susan','@Susan'],['Foo','&Foo'],['Bar','&Bar']]
      let words = split(getline('.'), '\W\+')
      let appendix = ''
      for word in words
        for item in listodo
          if word == item[0]
            let appendix = appendix . ' ' . item[1]
          endif
        endfor
      endfor
      call setline(line('.'), getline('.') . appendix)
    endfunction
    

    【讨论】:

    • 什么?!有has_key,两个周期就不需要了。
    • 我使用has_key 的变体是不是很幼稚?顺便说一句,只有我的解决方案不允许重复标签(假设您没有 Tom 和 Thomas 在一行中)(也不检查已经存在的标签)。
    • 我在这里反对,因为字典是保存此类数据的好选择,而items()-like list 则不是。 “什么?!” == “你为什么要使用无缘无故增加问题的结构?!”
    • 答案:因为我是新手“vimscripter”。我一点也不熟悉 Vim 的数据结构和函数,比如has_key()。但我在学习!和不。您的变体根本不是“天真的”。你的两个回答让我了解了has_key()map()filter(),这无疑会很方便。
    • 从来没有像新手 vimscripter 那样想到你:对 vim 标签的回复太多了,不能这么想。而map()/filter() 并不是我对这个问题的唯一答案(尽管它们比我一开始想的更方便:我有时用它们来替换循环:利用add()/@987654332 的副作用@/extend()/insert() 在这些函数的第二个参数中提高了性能,有时甚至显着提高了性能,但代价是使代码更加神秘)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 2012-01-29
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    相关资源
    最近更新 更多