【问题标题】:Exact pattern match using perl index() function使用 perl index() 函数的精确模式匹配
【发布时间】:2021-05-02 09:10:38
【问题描述】:

我正在尝试使用 index() 函数,并且我想找到一个单词在字符串中的位置,只有当它完全匹配时。例如:

我的字符串是STRING="CATALOG SCATTER CAT CATHARSIS"

我的搜索字符串是KEY=CAT

我想说index($STRING, $KEY) 之类的内容并检查 CAT 的匹配,而不是 CATALOG。我该如何做到这一点?文档说

index 函数在另一个字符串中搜索一个字符串,但没有完整正则表达式模式匹配的类似通配符的行为。

这让我觉得这可能不是那么直截了当,但我的 perl 技能是有限的 :)。有可能做我想做的事吗?

希望我能够很好地表达我的问题。提前感谢您的帮助!

【问题讨论】:

  • 你的意思是cat子字符串只有在它前后没有字母时才应该被“找到”?这正是正则表达式的用途。虽然在技术上可以使用index(检查结果位置之前和结果位置之后的符号+键的长度),但至少可以这么说。
  • 你想要一个正则表达式。这个问题一直是asked before

标签: perl


【解决方案1】:

怎么样:

my $str = "CATALOG SCATTER CAT CATHARSIS";
my $key = "CAT";
if ($str =~ /\b$key\b/) {
    say "match at char ",$-[0];;
} else {
    say "no match";
}

输出:

match at char 16

【讨论】:

  • 谢谢大家的信息。我将使用模式匹配而不是 index()。 (在正确的地方了解正确的西装需要一些时间;-))
【解决方案2】:

您需要了解 Perl 中的 Regular Expressions。 Perl 并没有发明正则表达式,而是极大地扩展了这个概念。事实上,许多其他编程语言都专门讨论使用 Perl 正则表达式

正则表达式匹配特定的单词模式。例如,/cat/ 匹配字符串中的序列 cat

if ( $string =~ /cat/ ) {
    print "String contains the letters 'cat' in a row\n";
}

在许多方面,这与以下内容相同:

my $location = index ( $string, "cat" );
if ( $location =! -1 ) {  # index returns -1 when substring isn't found
    print "String contains the letters 'cat' in a row\n";
}

但是,这两个都会匹配:

  • "Don't let the cat out of the bag"
  • "The Sears catalog arrived in the mail"

您不想匹配最后一个。所以,你可以这样做:

 my $location = index $string, " cat ";

现在,index $string, " cat " 将与单词 catalog 不匹配。结案!或者是吗?怎么样:

  • "cat and dog it doth rain."

如果句子以“cat”开头,也许你可以检查并说没问题:

if ( (index ($string, " cat ") != -1) or (index ($string, "cat") = 0) ) {
    print "String contains the letters 'cat' in a row\n";
}

但是,这些呢?

  • "The word CAT in all uppercase"
  • "Stupid cat"
  • "Cat! Here Cat! Common Cat!":“猫”后面的标点符号
  • "Don't let the 'cat' out of the 'bag'": "cat" 两边的引号

可能需要几十行来指定这些条件中的每一个。

但是:

if ( $string =~ /\bcat\b/i ) {
    print "String contains the word 'cat' in it\n";
}

指定每一个 -- 然后是一些。 \b 表示这是一个单词边界。这可以是空格、制表符、引号、行的开头或结尾。因此/\bcat\b/ 指定这应该是单词cat 而不是catalog。末尾的 i 告诉您的正则表达式在匹配时忽略大小写,因此您会找到 CatcatCATcAt 以及所有其他可能的组合。

事实上,正是 Perl 的正则表达式使 Perl 成为如此流行的语言。

幸运的是,Perl 提供了两个关于正则表达式的教程:

希望这会有所帮助。

【讨论】:

  • 解释得很好。阅读这个答案可能是进入正则表达式世界的第一步。
【解决方案3】:

这是index这个问题的(部分)解决方案:

use warnings;
use strict;

my $test = 'CATALOG SCATTER CAT CATHARSIS';
my $key = 'CAT';

my $k_length = length $key;
my $s_length = (length $test) - $k_length;

my $pos      = -1;
while (($pos = index $test, $key, $pos + 1) > -1) {
  if ($pos > 0) {
    my $prev_char = substr $test, $pos - 1, 1;
    ### print "Previous character: '$prev_char'\n";
    next if $prev_char ge 'A' && $prev_char le 'Z'
         || $prev_char ge 'a' && $prev_char le 'z';
  }
  if ($pos < $s_length) {
    my $next_char = substr $test, $pos + $k_length, 1;
    ### print "Next character: '$next_char'\n";
    next if $next_char ge 'A' && $next_char le 'Z'
         || $next_char ge 'a' && $next_char le 'z';
  }
  print "Word '$key' found at " . $pos + 1 . "th position.\n";
}

如您所见,它有点罗嗦,因为它只使用基本的 Perl 字符串函数 - indexsubstr。通过检查其下一个和前一个字符(如果它们存在)来检查找到的子字符串是否确实是一个单词:如果它们属于A-Za-z 范围,则它不是一个单词。

您可以通过尝试将这些字符小写(使用 lc)来简化它,然后仅检查单个字符范围:

my $lc_prev_char = lc( substr $test, $pos - 1, 1 );
next if $lc_prev_char ge 'a' && $lc_prev_char le 'z';

...但话又说回来,这是一个很小的改进(如果有改进的话)。

现在考虑一下:

my $test = 'CATALOG SCATTER CAT CATHARSIS CAT';
my $key = 'CAT';
while ($test =~ /(?<![A-Za-z])$key(?![A-Za-z])/g) {
  print "Word '$key' found at " . ($-[0] + 1) . "th position.\n";
}

...就是这样!该模式从字面上测试给定字符串 ($test) 的子字符串 ($key) 前面或后面不是 A-Za-z 范围的符号,并且支持 Perl 正则表达式魔法(特别是this variable)可以轻松获取此类子字符串的起始位置。

底线:使用正则表达式来完成正则表达式的工作。

【讨论】:

    【解决方案4】:

    正则表达式允许搜索包含单词边界以及不同的字符。而

    my $string = "CATALOG SCATTER CAT CATHARSIS";
    index($string, 'CAT');
    

    如果$string 包含字符CAT,将返回零或更大,如正则表达式

    $string =~ /\bCAT\b/;
    

    将返回false,因为$string 不包含CAT 前后是单词边界。 (单词边界是字符串的开头或结尾,或者介于单词字符和非单词字符之间。单词字符是任何字母数字字符或下划线.)

    【讨论】:

      【解决方案5】:

      使用 \E 值。 所以:

      #!usr/bin/perl
      
      my $string ="Little Tony";
      my $check = "Ton";
      
      if($string =~ m/$check\E/g)
      {
      print "match";
      }
      else 
      { 
      die("No Match"); 
      }
      

      【讨论】:

      • 在 OP 问题中,这不应该匹配,但它确实匹配,因为 \E 不是用于此目的的相关转义。 \E 结束字符修改,例如阻止元字符或更改字符串的大小写。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      • 1970-01-01
      • 2016-12-20
      • 2012-03-29
      • 2020-10-12
      相关资源
      最近更新 更多