Regex 自动完成的正则表达式

Regex 自动完成的正则表达式,regex,Regex,我有一个短语列表,由空格、连字符、camelCase或PascalCase组成。我希望能够通过只键入每个单词的几个字母,或者跳过一些单词来过滤这些短语。 对于那些熟悉JetBrains的IDE的人来说,这类似于代码完成的工作方式。我希望模拟这种行为是为了一般目的,而不仅仅是为了在IDE中编写代码。(一般用途是在网站中使用它来过滤短语,可能与Bash一起使用它来获取文件列表,只需键入文件单词的前几个字母,或者如我所说的某些单词)。这是我经常使用的非常方便的工具(在JetBrains中) 示例: 给

我有一个短语列表,由空格、连字符、camelCase或PascalCase组成。我希望能够通过只键入每个单词的几个字母,或者跳过一些单词来过滤这些短语。 对于那些熟悉JetBrains的IDE的人来说,这类似于代码完成的工作方式。我希望模拟这种行为是为了一般目的,而不仅仅是为了在IDE中编写代码。(一般用途是在网站中使用它来过滤短语,可能与Bash一起使用它来获取文件列表,只需键入文件单词的前几个字母,或者如我所说的某些单词)。这是我经常使用的非常方便的工具(在JetBrains中)

示例
给出以下短语:

  • LoremIpsumDolor
  • sitametconcectetur
  • adipising elit sed
  • Do Eiusmod Tempor incidedunt
以下是我想筛选的一些典型词语:

  • lodo
    ->返回
    LoremIpsumDolor
    (注意这里的大小写不敏感,这是我想要的方式)
  • dotemporinc
    ->回馈
    是否执行Eiusmod临时登录
  • Do
    ->返回
    LoremIpsumDolor
    Do Eiusmod Tempor incidount
  • ac
    ->返回
    sitametconcectur
我一直在考虑如何实现这种功能,我能想到的最好办法是,键入示例1中的单词进行过滤,比如说
lodo
,将生成一个由单词字母构成的正则表达式,由一些额外的表达式分隔,形成整个正则表达式。。。然后,它将根据该正则表达式测试列表中的每个短语,并仅返回匹配的短语

我想把单词(
lodo
)拆分成几个字母,在每个字母之间(开头和结尾)放上下面的regexp:
([a-zA-Z][a-Z]*)*
,(这个解决方案,如果可行的话,假设所有短语都是camel\pascalcated,但完整的解决方案必须包括其他情况)。这将导致以下regexp:
^([a-zA-Z][a-Z]*)*[lL]([a-zA-Z][a-Z]*)*[oO]([a-zA-Z][a-Z]*)*[dD]([a-zA-Z][a-Z]*)[oO]([a-zA-Z][a-Z]*)*$

显然,这有一些源自回溯的巨大缺陷,更具体地说,我认为(但显然不确定),如果我可以在
([a-zA-Z][a-Z]*)*
中禁用内部星表达式的回溯,只保留外部星的回溯,它应该可以工作


我希望我解释得足够好。也许这个问题有一个已知的解决方案,那么我很想听听。

在考虑了几个小时后,我用正则表达式设计了一个解决方案,我真的认为这是一个非常适合这个问题的解决方案,而且真的没有那么难

我的解决方案目前只处理camelCase和PascalCase短语(即,它只能正确过滤使用camelCase或PascalCase编写的短语),但将其应用于其他情况应该很容易。就目前而言,这些案例已经足够好了

下面是我的想法:

给定一个单词,比如我上面的例子中的
lodo
,你应该意识到,对于给定单词中的每个字母(
l
o
d
o
),它可以是单词的第一个字母(意味着它应该匹配大写字母,或者如果它是第一个单词,它也可能是小写),或者它是我们之前找到的单词中的下一个字母(表示它是小写的,应该在我们已经找到前一个字母后立即尝试匹配)。 我们还应该考虑正则表达式的行为,准确地说,还要考虑子表达式的求值顺序。我们将使用这样一个事实,即在or表达式(
|
)中,首先尝试左侧,在形式为
e*?
(javascript)的表达式中,它将找到尽可能最小的匹配项(与省略问号相反,在这种情况下,它将消耗尽可能多的字符,那么我们可能会进入回溯情况,这对我们不利)

那么,让我们构造regexp。对于每个字符c,我们构造:

  • 如果c是我们的第一个字母(在
    lodo
    中,它的意思是
    l
    ),那么:

    • 为了让c匹配第一个单词的第一个字母,它可以是小写,我们构造:
      (^c)
    • 否则它必须是其他单词的第一个字母,并且必须是大写,我们构造:
      C
    • 我们对第一个字母的表达:
      (^c|c)
  • 否则:

    • 我们想首先测试我们的字母是否是我们已经找到的单词开头的延续。因此,我们的c字母(在
      lodo
      中,此参数对
      o
      d
      o
      )中的任何一个都有效)在这种情况下必须是小写的,并且我们构造
      (c)
    • 否则,c必须是新词中的第一个字母,这意味着它必须是大写字母,我们还必须考虑为以前的字母构造的正则表达式,因此我们必须使用当前所在的整个单词,然后尝试使用其他单词,但我们优先使用大写字母
      c
      字母(希望这个解释是清楚的)。对于这种情况,我们构造
      [a-z]*([a-z][a-z]*)*?C
      [a-z]*
      )用于使用当前单词的剩余字母,如果
      [a-z][a-z]*?
      不是下一个单词的第一个字母,则构造
      ([a-z][a-z]*)*?
      (请记住,它可以是前面两个单词的下一个字母,因此……这是我的要求))
    • 我们对任何非首字母的表达:const searchData = searchText => { const regex = new RegExp(searchText, 'gi'); return new Promise(resolve => resolve(topMovies.filter(m => m.title.match(regex)))) }; const topMovies = [{title: "The Shawshank Redemption (1994)", rating: 9.2 },{title: "The Godfather (1972)", rating: 9.2 },{title: "The Godfather: Part II (1974)", rating: 9.0 },{title: "The Dark Knight (2008)", rating: 9.0 },{title: "12 Angry Men (1957)", rating: 8.9 },{title: "Schindler's List (1993)", rating: 8.9 },{title: "The Lord of the Rings: The Return of the King (2003)", rating: 8.9 },{title: "Pulp Fiction (1994)", rating: 8.9 },{title: "The Good, the Bad and the Ugly (1966)", rating: 8.8 },{title: "Fight Club (1999)", rating: 8.8 },{title: "The Lord of the Rings: The Fellowship of the Ring (2001)", rating: 8.8 },{title: "Forrest Gump (1994)", rating: 8.7 },{title: "Star Wars: Episode V - The Empire Strikes Back (1980)", rating: 8.7 },{title: "Inception (2010)", rating: 8.7 },{title: "The Lord of the Rings: The Two Towers (2002)", rating: 8.7 },{title: "One Flew Over the Cuckoo's Nest (1975)", rating: 8.7 },{title: "Goodfellas (1990)", rating: 8.7 },{title: "The Matrix (1999)", rating: 8.6 },{title: "Seven Samurai (1954)", rating: 8.6 },{title: "City of God (2002)", rating: 8.6 },{title: "Star Wars: Episode IV - A New Hope (1977)", rating: 8.6 },{title: "Se7en (1995)", rating: 8.6 },{title: "The Silence of the Lambs (1991)", rating: 8.6 },{title: "It's a Wonderful Life (1946)", rating: 8.6 },{title: "Life Is Beautiful (1997)", rating: 8.6 },{title: "The Usual Suspects (1995)", rating: 8.5 },{title: "Spirited Away (2001)", rating: 8.5 },{title: "Saving Private Ryan (1998)", rating: 8.5 },{title: "Léon: The Professional (1994)", rating: 8.5 },{title: "Avengers: Infinity War (2018)", rating: 8.5 },{title: "The Green Mile (1999)", rating: 8.5 },{title: "Interstellar (2014)", rating: 8.5 },{title: "American History X (1998)", rating: 8.5 },{title: "Psycho (1960)", rating: 8.5 },{title: "City Lights (1931)", rating: 8.5 },{title: "Once Upon a Time in the West (1968)", rating: 8.5 },{title: "Casablanca (1942)", rating: 8.5 },{title: "Modern Times (1936)", rating: 8.5 },{title: "The Intouchables (2011)", rating: 8.5 },{title: "The Pianist (2002)", rating: 8.5 },{title: "The Departed (2006)", rating: 8.5 },{title: "Terminator 2 (1991)", rating: 8.5 },{title: "Back to the Future (1985)", rating: 8.5 },{title: "Rear Window (1954)", rating: 8.5 },{title: "Raiders of the Lost Ark (1981)", rating: 8.5 },{title: "Whiplash (2014)", rating: 8.5 },{title: "Gladiator (2000)", rating: 8.5 },{title: "The Lion King (1994)", rating: 8.5 },{title: "The Prestige (2006)", rating: 8.5 },{title: "Memento (2000)", rating: 8.4 }]; const searchInputElement = document.querySelector('.search-input'); const resultsElement = document.querySelector('.results'); // Convert search results into UI suggestions function showSearchResults(searchQuery) { searchData(searchQuery).then(results => { const html = results.map(movie => ` <li> <span class="title">${movie.title}</span> <span class="rating">${movie.rating}</span> </li> `); resultsElement.innerHTML = html.join(''); }); } // Pass function handleChange() { return showSearchResults(this.value); } // Register for both events searchInputElement.addEventListener('change', handleChange); searchInputElement.addEventListener('keyup', handleChange); //HTML <form class="search-form"> <input type="text" class="search-input" placeholder="Start typing a movie title..."> <ul class="results"></ul> </form>