简体   繁体   English

在Perl中使用grep

[英]Using grep in Perl

I have the below code snippet. 我有以下代码片段。 I need to insert a grep command in the appropriate place to find only grades between 80 and 89 and store them in a separate array called @GradeB . 我需要在适当的位置插入grep命令,以仅查找80到89之间的成绩并将它们存储在名为@GradeB的单独数组中。 I've tried using @GradeB = grep("8[0-9]", @Grades); 我试过使用@GradeB = grep("8[0-9]", @Grades); , but that puts everything into @GradeB . ,但这会将所有内容放入@GradeB Where am I going wrong to get only grades between 80-89 into @GradeB ? 我在哪里犯错,所以只能将@GradeB分数在80-89之间? For full disclosure, this is is homework, but I am allowed to use any and all resources available to me. 为了全面披露,这是家庭作业,但是我可以使用任何可用的资源。

@Grades = ("Name: Shemp      Grade: 82",
           "Name: Curly      Grade: 62",
           "Name: Curly Joe  Grade: 58",
           "Name: Joe        Grade: 50",
           "Name: Moe        Grade: 88",
           "Name: Larry      Grade: 82");


# grep command here
print join("\n", @GradeB);

Take look at perldoc for grep : 看看grep perldoc:

   grep BLOCK LIST
   grep EXPR,LIST

Grep evaluates BLOCK or EXPR for every element of LIST and returns list composed of elements for which BLOCK or EXPR evaluate to true value. Grep对LIST每个元素评估BLOCKEXPR ,并返回由BLOCKEXPR评估为真值的元素组成的列表。 As you specify string "8[0-9]" , which is always true, every list element is returned. 当您指定始终为true的字符串 "8[0-9]" ,将返回每个列表元素。

You need to pass regular expression as EXPR : 您需要将正则表达式作为EXPR传递:

@GradeB = grep /8[0-9]/, @Grades;

It is best not to use capitals for lexical variable names. 最好不要将大写形式用于词汇变量名称。

This solution works by extracting the string of digits that follow Grade: and comparing it with the specified range. 此解决方案的工作原理是提取“ Grade:的数字字符串,并将其与指定范围进行比较。

use strict;
use warnings;

my @grades = (
  "Name: Shemp      Grade: 82",
  "Name: Curly      Grade: 62",
  "Name: Curly Joe  Grade: 58",
  "Name: Joe        Grade: 50",
  "Name: Moe        Grade: 88",
  "Name: Larry      Grade: 82",
);

print "$_\n" for grep {
  /grade\s*:\s*(\d+)/i and $1 >= 80 and $1 < 90;
} @grades;

output 输出

Name: Shemp      Grade: 82
Name: Moe        Grade: 88
Name: Larry      Grade: 82

grep returns each item in a list for which the expression evaluates to true. grep返回列表中的每个项目,表达式的计算结果为true。 The expression 表达方式

"8[0-9]"

is a string, and it always evaluates to true. 是一个字符串,并且始终为true。 You probably meant to use a regular expression instead: 您可能打算改用正则表达式:

my @b_grades = grep /Grade: 8[0-9]$/, @grades;
# Alternately, my @b_grades = grep { /Grade: 8[0-9]$/ } @grades;

Note that I've used a more specific regex than just /8[0-9]/ , which would match things like: 请注意,我使用了比/8[0-9]/更具体的正则表达式,它将匹配以下内容:

Name: Inmate 12789132    Grade: 12

This approach works, but isn't very flexible. 这种方法有效,但不是很灵活。 As Borodin points out in the comments, changing the regex to match scores between, say, 79 and 88 is difficult. 正如Borodin在评论中指出的那样,很难更改正则表达式以使其得分介于79和88之间。 It would be better to extract the scores so we can do numerical comparisons: 最好提取分数,以便我们进行数值比较:

my @b_grades = grep {
                        if (/Grade: (\d+)$/)  {
                            $1 if ($1 >= 80 && $1 < 90);
                        }
                    } @grades;

This is just a different way of writing Borodin's solution . 这只是编写Borodin解决方案的另一种方式。


Note that an array is not the best choice of data structure for this. 请注意,为此,数组并不是数据结构的最佳选择。 When you have a list of key/value pairs, think "hash." 当您具有键/值对的列表时,请考虑“哈希”。 In this case, you can use names as keys and grades as values: 在这种情况下,可以将名称用作键,将等级用作值:

my %grades = (
    Shemp       => 82,
    Curly       => 62,
    'Curly Joe' => 58,
    Joe         => 50,
    Moe         => 88,
    Larry       => 82
);

Note that quotes are optional around keys that only consist of letters, digits, and underscores. 请注意,在仅包含字母,数字和下划线的键周围,引号是可选的。 To access the values in the hash, use the aptly-named values function: 要访问哈希中的值,请使用适当命名的values函数:

my @grades = values %grades;

Using grep as before to get all the B's: 像以前一样使用grep获取所有B:

my @b_grades = grep { $_ >= 80 && $_ < 90 } values %grades;
print join ',', @b_grades;
# 88,82,82

This gives us a list of grades, but now we have no idea who they belong to. 这给了我们一个成绩清单,但是现在我们不知道他们属于谁。 For that, we need to use keys , which, strangely enough, returns a list of all the keys in our hash: 为此,我们需要使用keys ,这很奇怪,它返回哈希中所有键的列表:

my @b_students = grep { $grades{$_} >= 80 && $grades{$_} < 90 } keys %grades;
print "Name: $_\tGrade: $grades{$_}\n" for @b_students;
# Name: Moe       Grade: 88
# Name: Larry     Grade: 82
# Name: Shemp     Grade: 82

You can use a combination of map() and grep() . 您可以结合使用map()grep() The first one creates an arrayref to keep the whole line and the last number in it, the grep() compares them, and last map() extracts the whole line of those which matched: 第一个创建一个arrayref来保留整行,最后一行保留其中, grep()比较它们,最后map()提取匹配的整行:

#!/usr/bin/env perl

use warnings;
use strict;

my @Grades = ("Name: Shemp      Grade: 82",
           "Name: Curly      Grade: 62",
           "Name: Curly Joe  Grade: 58",
           "Name: Joe        Grade: 50",
           "Name: Moe        Grade: 88",
           "Name: Larry      Grade: 82");


# grep command here

my @GradeB = 
    map { $_->[0] } 
    grep { $_->[1] >= 80 and $_->[1] <= 89 } 
    map { [$_, (split)[-1]] } @Grades;

print join("\n", @GradeB);

It yields: 它产生:

Name: Shemp      Grade: 82
Name: Moe        Grade: 88
Name: Larry      Grade: 82

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM