Sunday, April 8, 2012

使用VIM搜索小技巧:不含有模式

VIM是我最喜欢用来搜索和替代文字的工具。这是最古老的文字编辑软件,也许许多人刚刚开始使用时为其用户界面所困扰,但是这是一个具有非常强大功能的软件,最初是由UNIX下的许多软件高手推出,经过多年来的补充和改进,现在几乎在所有的平台都可以下载免费的软件,它是许多编程人员爱不释手的高效率工具软件。

我最近遇到的问题是在众多的源程序中寻找满足tablespace的单字,但其后面的词不是以t开头的词。比如说tablespace temp就不是我需要寻找的内容,而tablespace pmdb就是我希望找到的内容。确认所有这些找到的内容之后,我需要将它们更换为我需要的内容。如果手动在几百个源程序中一一寻找,其工作量是非常巨大的。因此我想到了VIM。

VIM的基本搜索方式


首先回到VIM是基本搜索方式,下面是如何在VIM进行搜索的指令:

/pattern

这里/是表示开始进行搜索,pattern是搜索的内容或模式,这个模式可以是Regex表达式。Regex是编程中非常强大用于表达搜索内容的表达式,有关这一方面的内容可以十分丰富,这里就不再相信解释了。

环顾继续搜索


我所需要的搜索不仅仅是满足一个模式,而是在满足模式部分内容的条件下,进一步要求不含有某些内容,比如满足tablespace,但其后不包括有t开头的词。我最初以为在VIM中有这样搜索的模式,但是经过网络搜索和研究之后,我发现VIM在处理这个问题上采用的是更为巧妙的方式。

这就是lookahead zero width assertion或lookbehind zero width assertion,简言之,是进一步搜索前或后的内容作为搜索的满足条件,但是这种进一步的搜索的内容,不作为最后的搜索结果,因此称之为zero width,assertion是符合或不符合的意思。我这里将这些搜索的方式通称之为环顾继续搜索。

环顾继续搜索的表达方式为下面四种情况:

/PATTERN[ZERO_WIDTH_ATOM\@=]
/PATTERN[ZERO_WIDTH_ATOM\@!]
/[ZERO_WIDTH_ATOM\@<=]PATTERN
/[ZERO_WIDTH_ATOM\@


其中pattern是搜索的内容,搜索的结果将在VIM中标示出来,而zero width atom是进一步搜索的条件:或前或后,atom是VIM中的术语,表示一个字符或一个组;其搜索的条件是满足或不满足。这里我将这些特殊的表述总结为下面的表:

\@表述向前 lookahead
\@表示向后 lookbehind
=符合 positive match
!不符合 negative or not match.

用编程的逻辑来理解VIM的搜索


这里我可以用下面的c风格表述程序(pseudo codes)来描述VIM的搜索逻辑:

Results getMatchedResults(
   string context,               // basic
   string pattern,
   string zero_width_pattern,    // zero_width pattern
   bool match_zero_width_pattern,
   bool lookahead)
{
  results = EMPTY_LIST;
  result = getMatchedResult(context, pattern);
  while (result != EMPTY)
  {
    if (zero_pattern != EMPTY)
    {
      if ( lookahead ) {
        context_tmp = getNextContextByLookahead(context, result);
        result_tmp = getMatchedResult(context_tmp, zero_width_pattern);
      } else {
        context_tmp = getNextContextByLookbehind(context, result);
        result_tmp = getMatchedResultByLookbehind(context_tmp,
                       zero_width_pattern);
      }
      if ( result_tmp == EMPTY ) {
        if (match_zero_width_pattern) {
          result = EMPTY;
        }
      } else {
        if (!match_zero_width_pattern) {
          retult = EMPTY;
        }
      }
    }
    if ( result != EMPTY ) {
      results.add(result);
      context = geNextContextByLookahread(context, result);
      result = getMatchedResult(context, pattern);
    }
  }
  return results;
}

上面的表述程序非常直观地解释了VIM的搜索逻辑,这里不必详细解释了。下一文将就此应用举出数个例子,届时将可以看到VIM搜索的强大功能。

参考


No comments:

Post a Comment