Part I: Data Structure Design
感谢 glhezjnucn 童鞋的给力翻译
First, let’s talk about one specific RSS feed: Google News. The URL for the Google News feed is: 首先我们讨论一个特定的RSS推送:Google新闻。链接如下
http://news.google.com/?output=rss
If you try to load this URL in your browser, you’ll probably see your browser’s interpretation of the XML code generated by the feed. You can view the XML source with your browser’s “View Page Source” function, though it probably will not make much sense to you. Abstractly, whenever you connect to the Google News RSS feed, you receive a list of items. Each entry in this list represents a single news item. In a Google News feed, every entry has the following fields:
如果你用浏览器打开这个网址,那么你的浏览器会将XML生成为页面反馈信息,你可以用查看源代码的功能看XML的源码,不过这也许没多大帮助。 简略的说,当你链接一个Google 新闻RSS推送时,你会得到一个项目列表,每个条目表示一条单一的新闻,在Google新闻条目里,含有以下信息:
- guid : A globally unique identifier for this news story. 全局唯一的新闻条目的识别号
- title : The news story’s headline. 新闻条目的标题
- subject : A subject tag for this story (e.g. ‘Top Stories’, or ‘Sports’). 新闻条目的主题(比如 ‘Top Stories’, 或 ‘Sports’).
- summary : A paragraph or so summarizing the news story.新闻条目的概要或段落ry.
- link : A link to a web-site with the entire story. 新闻条目的完整链接网址
Generalizing the Problem 问题的一般化
This is a little trickier than we’d like it to be, because each of these RSS feeds is structured a little bit differently than the others. So, our goal in Part I is to come up with a unified, standard representation that we’ll use to store a news story.
比我们希望的要棘手一点,每个RSS推送器可能在信息组织格式上不太一样。因此,第一部分我们的目标是统一,标准化存储新闻条目。
Why do we want this? When all is said and done, we want an application that aggregates several RSS feeds from various sources and can act on all of them in the exact same way: we should be able to read news stories from various RSS feeds all in one place. If you’ve ever used an RSS feed reader, be assured that it has had to solve the exact problem we’re going to tackle in this pset!
为什么需要这样?当我们完成了这样的统一,我们的应用程序可以对聚集一起的多个RSS推送器看成完全是同一个。也就是我们在一个地方就可以阅读来自不同RSS推送器的新闻条目。要是你用过RSS阅读器,那就会相信它首先就要解决我们所面临的一模一样的问题。Problem 1
Parsing is the process of turning a data stream into a structured format that is more convenient to work with. We have provided you with code that will retrieve and parse the Google and Yahoo news feeds. 分列(parse语句)是处理数据流使之成为结构化格式,更适于工作的过程。我们已经为你提供了获取与分列Google, Yahoo新闻推送的代码。
Parsing all of this information from the feeds that Google/Yahoo/the New York Times/etc. gives us is no small feat. So, let’s tackle an easy part of the problem first: Pretend that someone has already done the specific parsing, and has left you with variables that contain the following information for a news story:
获取与分列来自Google/Yahoo/the New York Times等等的信息并非易事。因此让我们先来对付一个简单的部分问题:就像别人已经为我们做了这些提取与分列的工作,留给你的是关于新闻条目的如下信息:
- globally unique identifier (GUID) - a string that serves as a unique name for this entry 条目的唯一识别字符串
- title - a string 字符串
- subject - a string 字符串
- summary - a string 字符串
- link to more content - a string 字符串
We want to store this information in an object that we can then pass around in the rest of our program. Your task, in this problem, is to write a class, NewsStory, starting with a constructor that takes (guid, title, subject, summary, link) as arguments and stores them appropriately. NewsStory also needs to contain the following methods:
我们希望用对象来存储这些信息,然后可以将它传给程序的其他地方。你的任务是写一个class, NewsStory,以(guid, title, subject, summary, link)作为参数的一个构造器,并将它们合理的存储,NewsStory也需要如下方法
getGuid(self)
getTitle(self)
getSubject(self)
getSummary(self)
getLink(self)
Each method should return the appropriate element of an instance. For example, if we have implemented the class and call
test = NewsStory('foo', 'myTitle', 'mySubject', 'some long summary', 'www.example.com')
每个方法需要能返回实例的对应元素,例如,当我们实现了class定义,调用
then test.getGuid() will return foo.
The solution to this problem should be relatively short and very straightforward (please review what get methods should do if you find yourself writing multiple lines of code for each). Once you have implemented NewsStory all the NewsStory test cases should work.
对这个问题的解答应该是相对简短而非常直接的。当你实现了NewsStrory,那所有的NewssTory测试都应该通过。
To test your class definition, we have provided a test suite in ps7_test.py. You can test your code by loading and running this file. You should see an “OK” for the NewsStory tests if your code is correct. Because ps7.py contains code to run the full RSS scraping system, we suggest you do not try to run ps7.py directly to test your implementation. Instead, in IDLE, you can do the following:
>>> from ps7 import *
>>> test = ps7.NewsStory('foo', 'myTitle', 'mySubject', 'some long summary', 'www.example.com')
to load in then run your own tests on your class definitions.
为测试你的class定义,我们在ps7_test.py中提供了测试集。你可以装入运行那个程序来测试你的代码。如果你的代码正确,应该看到NewssTory测试OK这样的信息,我们提议你不直接运行ps7.py来测试你的实现。而是,在IDLE环境用下列代码来测试:
# Enter your code for NewsStory in this box
class NewsStory(object):
def __init__(self,guid,title,subject,summary,link):
self.guid = guid
self.title = title
self.subject = subject
self.summary = summary
self.link = link
def getGuid(self):
return self.guid
def getTitle(self):
return self.title
def getSubject(self):
return self.subject
def getSummary(self):
return self.summary
def getLink(self):
return self.link
Part II: Word Triggers
Given a set of news stories, your program will generate alerts for a subset of those stories. Stories with alerts will be displayed to the user, and the other stories will be silently discarded. We will represent alerting rules as triggers. A trigger is a rule that is evaluated over a single news story and may fire to generate an alert. For example, a simple trigger could fire for every news story whose title contained the word “Microsoft”. Another trigger may be set up to fire for all news stories where the summary contained the word “Boston”. Finally, a more specific trigger could be set up to fire only when a news story contained both the words “Microsoft” and “Boston” in the summary.
给定一组新闻条目,你的程序需要为一个子集生成通知(alerts),附带alert的条目将显示给用户,而其他就无声地丢弃。 我们将用触发器来表示通知规则。一个触发器是用于评估单一的新闻条目是否需要被通知的规则。比如,一个简单的触发器可能是触发所有在title中含有单词”Microsoft”的新闻条目,另一个触发器可能是触发在summary中含有单词”Boston”的新闻条目。而进一步的特定触发器可能触发在summary中同时含有这两个单词的。
In order to simplify our code, we will use object polymorphism. We will define a trigger interface and then implement a number of different classes that implement that trigger interface in different ways.
为了简化我们的代码,我们采用对象的多态性,我们定义一个触发器界面,然后定义一系列不同的类来以不同的形式实现触发器界面。Trigger interface 触发器界面
Each trigger class you define should implement the following interface, either directly or transitively. It must implement the evaluate method that takes a news item (NewsStory object) as an input and returns True if an alert should be generated for that item. We will not directly use the implementation of the Trigger class, which is why it throws an exception should anyone attempt to use it
你定义的每个触发器类应该直接或间接地实现如下界面。它必须实现evaluate方法,接收新闻条目输入(NewsStory类),如果该条目需要通知就返回True.我们不直接用Trigger类里定义的evaluate,这就是为什么那里写了如果被引用的话就产生一个exception出错。
The class below implements the Trigger interface (you will not modify this). Any subclass that inherits from it will have an evaluate method. By default, they will use the evaluate method in Trigger, the superclass, unless they define their own evaluate function, which would then be used instead. If some subclass neglects to define its own evaluate() method, calls to it will go to Trigger.evaluate(), which fails (albeit cleanly) with the NotImplementedError exception:
下面的类定义实现触发器界面(你不要修改它).每个继承它的子类都需要有一个evaluate 方法. 缺省地,子类会引用Trigger类的evaluate方法,除非它定义了自己的evaluate,那么它将取代继承来的方法. 如果一些子类忽略了定义自己的evaluate()方法,那么对它的调用将转向Trigger.evaluate(), 这会失败 ,产生一个NotImplementedError例外:
class Trigger(object):
def evaluate(self, story):
"""
Returns True if an alert should be generated
for the given news item, or False otherwise.
"""
raise NotImplementedError
We will define a number of classes that inherit from Trigger. In the figure below, Trigger is a superclass, which all other classes inherit from. The arrow from WordTrigger to Trigger means that WordTrigger inherits from Trigger - a WordTrigger is a Trigger . Note that other classes inherit from WordTrigger.
我们将从Trigger类继承来定义一系列的子类。如下图所示(图请见原文),Trigger是超类,所有其他类继承它,WordTrigger继承Trigger,其他类又继承WordTrigger. (Trigger结构图略)Whole Word Triggers 完整单词触发器
Having a trigger that always fires isn’t interesting; let’s write some that are. A user may want to be alerted about news items that contain specific words. For instance, a simple trigger could fire for every news item whose title contains the word “Microsoft”. In the following problems, you will create a WordTrigger abstract class and implement three classes that inherit from this class.
我们对一个一直激发的触发器可能不感兴趣,我们要写一些有用的。用户可能对包含特定单词的新闻感兴趣,希望被通知。比如,一个简单的触发器可能是触发所有在title中含有单词”Microsoft”的新闻条目。在下面的问题,我们建立一个抽象类WordTrigger,然后继承它设计3个子类。
The trigger should fire when the whole word is present. For example, a trigger for “soft” should fire on: 当完整单词出现的时候,触发器应该被触发(激活),例如对单词”soft”的触发器应该就下列情形激活(激发)
- Koala bears are soft and cuddly.
- I prefer pillows that are soft.
- Soft drinks are great.
- Soft’s the new pink!
- “Soft!” he exclaimed as he threw the football.
But should not fire on: 但下列情形却不被激活(激发)
- Microsoft recently released the Windows 8 Consumer Preview.
- Downey makes my clothes the softest they can be!
This is a little tricky, especially the case with the apostrophe. For the purpose of your parsing, pretend that a space or any character in string.punctuation is a word separator. If you’ve never seen string.punctuation before, go to your interpreter and type: 这稍微有点棘手,尤其是有撇号的时候。在你分列词句时,可以认为空格或string.punctuation中的字符都是单词的分隔符。如果你从未看过string.punctuation,到解释器输入下面代码:
>>> import string
>>> print string.punctuation
Play around with this a bit to get comfortable with what it is.对它进行操作以便熟悉它,在这一部分,字符串的split与replace方法将有助于你解决问题。 同样你也可能用到lower或upper方法 The split and replace methods of strings will almost certainly be helpful as you tackle this part.
You may also find the string methods lower and/or upper useful for this problem.Problem 2
Implement a word trigger abstract class, WordTrigger. It should take in a string word as an argument to the class’s constructor.
设计单词触发器抽象类WordTrigger.
WordTrigger should be a subclass of Trigger. It has one new method, isWordIn, which takes in one string argument text. It returns True if the whole word word is present in text, False otherwise, as described in the above examples. This method should not be case-sensitive. Implement this method.
作为类构造的参数它接受一个单词字符串。 WordTrigger 必须是Trigger的子类. 它有一个新的方法isWordIn,它接收一个字符串参数text. 如果整个word含在text中返回True,否则返回False.这个方法不能对大小写敏感,实现它。
Because this is an abstract class, we will not be directly instantiating any WordTriggers. WordTrigger should inherit its evaluate method from Trigger. We do this because now we can create subclasses of WordTrigger that use its isWordIn method. In this way, it is much like the Trigger interface, except now actual code from this WordTrigger class is used in its subclasses.
因为它是一个抽象类,我们不直接实例化WordTrigger. WordTrigger需从Trigger继承evaluate方法。我们这么做是为了进一步定义WordTrigger的子类,而这些子类将继承它的isWordIn方法。因此它更像Trigger界面,只不过它的实际代码是在它的子类里调用。Problem 3
You are now ready to implement WordTrigger’s three subclasses: TitleTrigger, SubjectTrigger, and SummaryTrigger.
现在你可以开始设计WordTrigger的三个子类了: TitleTrigger, SubjectTrigger, 以及 SummaryTrigger.
Implement a word trigger class, TitleTrigger, that fires when a news item’s title contains a given word. The word should be an argument to the class’s constructor. This trigger should not be case-sensitive (it should treat “Intel” and “intel” as being equal).
设计单词触发器类TitleTrigger, 它激发新闻 title 中含有特定单词.单词作为类构造的参数,这个触发器也不分大小写(它对”Intel” 与”intel” 视为相等).
For example, an instance of this type of trigger could be used to generate an alert whenever the word “Intel” occurred in the title of a news item. Another instance could generate an alert whenever the word “Microsoft” occurred in the title of an item.
比如这个触发器类的一个实例可以激发title中含有单词”Intel”的新闻,而另一个实例可以激发title中含有”Microsoft”的新闻。
Think carefully about what methods should be defined in TitleTrigger and what methods should be inherited from the superclass. This class can be implemented in as few as 3 lines code!
考虑仔细,在TitleTrigger中该定义什么方法,又什么方法继承自它的超类。这个类的定义只须少于3行的代码来做。Problem 4
Implement a word trigger class, SubjectTrigger, that fires when a news item’s subject contains a given word. The word should be an argument to the class’s constructor. This trigger should not be case-sensitive.
设计单词触发器类SubjectTrigger, 它激发新闻 subject 中含有特定单词.单词作为类构造的参数,这个触发器也不分大小写.Problem 5
Implement a word trigger class, SummaryTrigger, that fires when a news item’s summary contains a given word. The word should be an argument to the class’s constructor. This trigger should not be case-sensitive.
设计单词触发器类SummaryTrigger, 它激发新闻 summary 中含有特定单词.单词作为类构造的参数,这个触发器也不分大小写.
# Enter your code for WordTrigger, TitleTrigger,
# SubjectTrigger, and SummaryTrigger in this box
class WordTrigger(Trigger):
def __init__(self,word):
self.word = word
def isWordIn(self,text):
for letter in text:
if letter in string.punctuation:
text = text.replace(letter,' ')
wordList = string.lower(text).split(' ')
return string.lower(self.word) in wordList
class TitleTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getTitle())
class SubjectTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSubject())
class SummaryTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSummary())
Part II: Composite Triggers
Composite Triggers 复合触发器
So the triggers from the previous page are mildly interesting, but we want to do better: we want to ‘compose’ the earlier triggers, to set up more powerful alert rules. For instance, we may want to raise an alert only when both “google” and “stock” were present in the news item (an idea we can’t express right now).
前面的触发器已经有点意思了,不过我们可以做得更好:我们将复合以前的触发器,来建立更为强大的通知准则。比如我们希望当新闻条目中同时含有”google” 和 “stock”时获得通知提醒(这一点我们现在还无法表达)。
Note that these triggers are not word triggers and should not be subclasses of WordTrigger.
注意这类触发器并非单词触发器,因此它不是WordTrigger的子类。Problem 6
Implement a NOT trigger (NotTrigger). 设计NotTrigger
This trigger should produce its output by inverting the output of another trigger. The NOT trigger should take this other trigger as an argument to its constructor. (Why its constructor? Because we can’t change what parameters evaluate takes in… that’d break our polymorphism). So, given a trigger T and a news item x, the output of the NOT trigger’s evaluate method should be equivalent to not T.evaluate(x).
这个触发器需要将别的触发器进行翻转输出。输入一个触发器对象作为参数,因此给定trigger T,新闻x,它的输出等效于 not T.evaluate(x).Problem 7
Implement an AND trigger (AndTrigger).设计AndTrigger
This trigger should take two triggers as arguments to its constructor, and should fire on a news story only if both of the inputted triggers would fire on that item.Problem 8
Implement an OR trigger (OrTrigger).
This trigger should take two triggers as arguments to its constructor, and should fire if either one (or both) of its inputted triggers would fire on that item.
# Enter your code for WordTrigger, TitleTrigger,
# NotTrigger, AndTrigger, and OrTrigger in this box
class WordTrigger(Trigger):
def __init__(self,word):
self.word = word
def isWordIn(self,text):
for letter in text:
if letter in string.punctuation:
text = text.replace(letter,' ')
wordList = string.lower(text).split(' ')
return string.lower(self.word) in wordList
class TitleTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getTitle())
class NotTrigger(Trigger):
def __init__(self,trigger):
self.trigger = trigger
def evaluate(self,story):
return not self.trigger.evaluate(story)
class AndTrigger(Trigger):
def __init__(self,trigger1,trigger2):
self.trigger1 = trigger1
self.trigger2 = trigger2
def evaluate(self,story):
return self.trigger1.evaluate(story) and self.trigger2.evaluate(story)
class OrTrigger(Trigger):
def __init__(self,trigger1,trigger2):
self.trigger1 = trigger1
self.trigger2 = trigger2
def evaluate(self,story):
return self.trigger1.evaluate(story) or self.trigger2.evaluate(story)
Part II: Phrase Triggers
Phrase Triggers 短语触发器
At this point, you have no way of writing a trigger that matches on “New York City” – the only triggers you know how to write would be a trigger that would fire on “New” AND “York” AND “City” – which also fires on the phrase “New students at York University love the city”. It’s time to fix this. Since here you’re asking for an exact match, we will require that the cases match, but we’ll be a little more flexible on word matching. So, “New York City” will match:
现在我们还没有办法写一个触发器来匹配查找短语 “New York City” – 你能写的触发器可能会是”New” , “York” , “City”作为单词触发器复合 – 但这样就会触发短语 “New students at York University love the city”. 这需要修正,因为我们需要你精确匹配,我们也需要区分大小,但在单词匹配上有一点灵活性 因此, “New York City” 能匹配如下:
- New York City sees movie premiere
- In the heart of New York City’s famous cafe
- New York Cityrandomtexttoproveapointhere
but will not match: 但不匹配下面的
- I love new york city
- I love New York City!!!!!!!!!!!!!!
Problem 9
Implement a phrase trigger (PhraseTrigger) that fires when a given phrase is in any of the story’s subject, title, or summary. The phrase should be an argument to the class’s constructor. You may find the Python operator in helpful, as in:
设计短语触发器(PhraseTrigger),当 新闻条目的subject, title, or summary 中任意一个含有该短语就会激发。短语需是类构建器的参数,你会发现Python的一下操作运算是有用的。
>>> print "New York City" in "In the heart of New York City's famous cafe"
True
>>> print "New York City" in "I love new york city"
False
# Enter your code for WordTrigger, TitleTrigger,
# SubjectTrigger, SummaryTrigger, and PhraseTrigger in this box
class WordTrigger(Trigger):
def __init__(self,word):
self.word = word
def isWordIn(self,text):
for letter in text:
if letter in string.punctuation:
text = text.replace(letter,' ')
wordList = string.lower(text).split(' ')
return string.lower(self.word) in wordList
class TitleTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getTitle())
class SubjectTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSubject())
class SummaryTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSummary())
class PhraseTrigger(Trigger):
def __init__(self,phrase):
self.phrase = phrase
def evaluate(self,story):
return self.phrase in story.getTitle() or self.phrase in story.getSubject() or self.phrase in story.getSummary()
Part III: Filtering 过滤
At this point, you can run ps7.py, and it will fetch and display Google and Yahoo news items for you in little pop-up windows. How many news items? All of them.现在你运行ps7.py,它会获取并以弹出窗口显示来自Google / Yahoo 的新闻条目,有多少呢?
Right now, the code we’ve given you in ps7.py gets all of the feeds every minute, and displays the result. This is nice, but, remember, the goal here was to filter out only the the stories we wanted.
所有. 现在, 我们在 ps7.py的代码每隔一分钟去提取显示一次,这挺不错,但记住,我们这里的目标是要设计一些过滤。Problem 10
Write a function, filterStories(stories, triggerlist) that takes in a list of news stories and a list of triggers, and returns a list of only the stories for which any of the triggers fires on. The list of stories should be unique - that is, do not include any duplicates in the list. For example, if 2 triggers fire on StoryA, only include StoryA in the list one time.
After completing Problem 10, run the file ps7_test.py. All the tests should now pass.
编写函数filterStories(stories, triggerlist),以参数输入新闻列表与触发器列表,返回任何触发器为True的新闻子集,新闻子集不该含有重复的条目。也就是说如果有2个触发器同时触发新闻StoryA,返回中指含一次StoryA 完成了Problem 10, 运行文件 ps7_test.py,应该通过全部测试.
# Enter your code for WordTrigger, TitleTrigger,
# SubjectTrigger, SummaryTrigger, PhraseTrigger, and
# filterStories in this box
# Enter your code for WordTrigger, TitleTrigger,
# SubjectTrigger, SummaryTrigger, PhraseTrigger, and
# filterStories in this box
# Enter your code for WordTrigger, TitleTrigger,
# SubjectTrigger, SummaryTrigger, PhraseTrigger, and
# filterStories in this box
class WordTrigger(Trigger):
def __init__(self,word):
self.word = word
def isWordIn(self,text):
for letter in text:
if letter in string.punctuation:
text = text.replace(letter,' ')
wordList = string.lower(text).split(' ')
return string.lower(self.word) in wordList
class TitleTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getTitle())
class SubjectTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSubject())
class SummaryTrigger(WordTrigger):
def __init__(self,word):
WordTrigger.__init__(self,word)
def evaluate(self,story):
return self.isWordIn(story.getSummary())
class PhraseTrigger(Trigger):
def __init__(self,phrase):
self.phrase = phrase
def evaluate(self,story):
return self.phrase in story.getTitle() or self.phrase in story.getSubject() or self.phrase in story.getSummary()
def filterStories(stories, triggerlist):
storyTriggerList=[]
for story in stories:
for trigger in triggerlist:
if trigger.evaluate(story):
storyTriggerList.append(story)
break
return storyTriggerList
Part IV: User-Specified Triggers 用户指定触发器
Right now, your triggers are specified in your Python code, and to change them, you have to edit your program. This is very user-unfriendly. (Imagine if you had to edit the source code of your web browser every time you wanted to add a bookmark!) 至此,你的触发器是指定在Python代码中的,要改变它们,你需要修改代码,这是非常用户-不友好的(谁想一下如果你想加个书签的话要更改浏览器代码)
Instead, we want you to read your trigger configuration from a triggers.txt file every time your application starts, and use the triggers specified there.我们希望运行应用程序时读入触发器配置文件triggers.txt,用那里指定的触发器。
Consider the following example trigger configuration file:
考虑如下的触发器配置文件:
# subject trigger named t1
t1 SUBJECT world
# title trigger named t2
t2 TITLE Intel
# phrase trigger named t3
t3 PHRASE New York City
# composite trigger named t4
t4 AND t2 t3
# the trigger set contains t1 and
t4
ADD t1 t4
The example file specifies that four triggers should be created, and that two of those triggers should be added to the trigger list:
例子指定生成4个触发器,其中的两个加载到触发器列表
- A trigger that fires when a subject contains the word ‘world’ (t1).
- A trigger that fires when the title contains the word ‘Intel’ and the news item contains the phrase ‘New York City’ somewhere (t4).
The two other triggers (t2 and t3) are created but not added to the trigger set directly. They are used as arguments for the composite AND trigger’s definition (t4).
另两个trigger (t2 and t3)建立起来但不直接加到触发器集合
Each line in this file does one of the following:
- is blank
- is a comment (begins with a #)
- defines a named trigger
- adds triggers to the trigger list. 将触发器加到触发器列表
Each type of line is described below. 每个行的类型描述如下
- Blank: blank lines are ignored. A line that consists only of whitespace is a blank line. 可以忽略
- Comments: Any line that begins with a # character is ignored.
- Trigger definitions: Lines that do not begin with the keyword ADD define named triggers. The first element in a trigger definition is the name of the trigger. The name can be any combination of letters without spaces, except for “ADD”. The second element of a trigger definition is a keyword (e.g., TITLE, PHRASE, etc.) that specifies the kind of trigger being defined. The remaining elements of the definition are the trigger arguments. What arguments are required depends on the trigger type:
不以关键词ADD开头的行用来定义一个触发器,第一个成分表示触发器的名称,名称定义是字母的组合(但不能用ADD)。第二成分是描述触发器类型的关键词(TITLE, PHRASE等),余下的是触发器需要的参数.需要什么样的参数取决于触发器的类型:
- TITLE : a single word.单一单词.
- SUBJECT : a single word.单一单词.
- SUMMARY : a single word.单一单词.
- NOT : the name of the trigger that will be NOT’d.触发器名称
- AND : the names of the two other triggers that will be AND’d.两个触发器名称
- OR : the names of the two other triggers that will be OR’d.t两个触发器名称.
- PHRASE : a phrase.一个短语.
- Trigger addition: A trigger definition should create a trigger and associate it with a name but should not automatically add that trigger to the running trigger list. One or more ADD lines in the .txt file will specify which triggers should be in the trigger list. An addition line begins with the ADD keyword. Following ADD are the names of one or more previously defined triggers. These triggers will be added to the the trigger list.
触发器的定义只是定义一个trigger并给它一个名称,并不直接加入到运行时的触发器列表。一个或多个ADD行才指定将什么trigger添加到运行时触发器列表。跟在ADD后面的是一个或多个前面已定义好的触发器,这些将加入到触发器列表。Problem 11
We have implemented the function readTriggerConfig(filename) for you. We’ve written code to open the file and throw away all the lines that don’t begin with instructions (e.g. comments and blank spaces), and then reads in the code that defines triggers and instantiates the triggers by making a call to the helper function makeTrigger. The function readTriggerConfig then returns a list of triggers specified in the configuration file.
我们为你写了函数readTriggerConfig(filename)。函数代码会打开trigger.txt文件并丢弃非指令的行,读入指令行并调用makeTrigger函数定义trigger以及trigger实例。
First, read through the definition of readTriggerConfig. You should be able to understand everything this function is doing at this point in the course. 首先通读readTriggerConfig函数的定义,在此你应该能完全理解函数的行为。
Next, implement the function makeTrigger(triggerMap, triggerType, params, name). This helper function should build and return a trigger depending on its type. It also keeps track of triggers and names in a map. We have defined for you the specifications for this function to make it easier for you to write. Be sure you understand how readTriggerConfig is using this function; that will make implementation easier.
然后实现函数makeTrigger(triggerMap, triggerType, params, name),这个函数实现按trigger的类型(译注:以前定义过的trigger类型)构建并返回一个trigger。而且它会在map中保持对trigger的跟踪(译注:也就是说构建新的trigger后需要将它刷新到trigger词典对照变量)。我们已经为你提供了一些特别指定,让你更容易的写出代码After completing Problem 11, you can try running ps7.py, and depending on how your triggers.txt file is defined, various RSS news items should pop up for easy reading. The code runs an infinite loop, checking the RSS feed for new stories every 60 seconds.完成了问题11,你可以试着运行ps7.py,它将取决于你的trigger.txt配置文件,不同的RSS新闻条目会以便于阅读的方式被推送出来。代码是无限循环的,每隔60秒检测一次RSS新闻条目。
# Enter your code for makeTrigger in this box
def makeTrigger(triggerMap, triggerType, params, name):
trigger = None
if triggerType == 'TITLE':
trigger = TitleTrigger(params[0])
elif triggerType == 'SUBJECT':
trigger = SubjectTrigger(params[0])
elif triggerType == 'SUMMARY':
trigger = SummaryTrigger(params[0])
elif triggerType == 'NOT':
t1 = triggerMap.get(params[0])
if t1 is not None:
trigger = NotTrigger(t1)
elif triggerType == 'AND':
t1 = triggerMap.get(params[0])
t2 = triggerMap.get(params[1])
if t1 is not None and t2 is not None:
trigger = AndTrigger(t1,t2)
elif triggerType == 'OR':
t1 = triggerMap.get(params[0])
t2 = triggerMap.get(params[1])
if t1 is not None and t2 is not None:
trigger = OrTrigger(t1,t2)
elif triggerType == 'PHRASE':
trigger = PhraseTrigger(string.join(params,' '))
if trigger is not None and name not in triggerMap.keys():
triggerMap[name] = trigger
return trigger