正则表达式 Skidmarklet





5.00/5 (2投票s)
从图钉到便便,你的书签栏可以做更多。阅读关于 Skidmarklet 的介绍……一个 JavaScript 书签小工具和正则表达式课程。
引言
正则表达式很难。阅读它们充其量是令人困惑和枯燥的。在你需要它们提供的功能之前,你很难理解它们为何存在。你需要将它们应用到你每天都在做的事情上。
按照这些课程,你将一步步组装一个 Skidmarklet……一个 JavaScript 书签小工具,它利用正则表达式匹配和替换功能,可以“涂抹”任何网页的糟糕部分。这么想吧,正则表达式(或 regex)很难,每个人都会拉屎,我们都能体会到这一点。
点击下面的按钮,即可看到成品效果,或在此处下载示例文件。
背景
最近初为人父的经历,重燃了我曾经肆虐的对便便的痴迷。所以,让我们把我的便便痴迷变成你的正则表达式吧!
我开发便便游戏是在 17 岁时,在 Blockbuster Video 工作的时候。别担心,那是在店里发生的,不是在厕所里。为了在填满磁带的单调工作中找点乐子,我把每个电影标题里的词都替换成“便便”。以《绿里奇迹》为例,有三种可能的便便游戏结果。
- 便便 绿里奇迹
- 便便奇迹
- 绿便便
一个词一个词地,我看着所有可能的组合哈哈大笑,顾客们也一个词一个词地,在我脑海里发生的一切中,离我诡异的咯咯笑声越来越远。在这里,便便让一份糟糕的工作不那么糟糕。正则表达式拥有传播快乐和喜悦的力量,只要我们能理解它们。所以,让我们通过在互联网上玩便便游戏来更好地了解它们吧。
第一课
将一个词列表替换成另一个词列表。它迭代一个正则表达式数组,使用一个特殊字符——单词边界——来确保我们只匹配整个单词。然后,我们可以确保它只替换单词“go”,而不是单词“engorge”中间的字母“go”。
1. 封装
我们必须确保我们只留下“污迹”,而不是堵塞马桶。在 JavaScript 术语中,最好避免冲突,作为一般指南,这意味着将主入口点封装在一个匿名函数调用中。所有主要功能都挤在一个名为“skidmark”的主方法中。
(function() {
!function skidmark(){
//Do some crap.
}();
})();
2. 定义一些变量
/* * CONSTANTS */
var POOP = "Poop";
var PATTERNS_TO_GO = [/\bgo\b/g,/\bgoing\b/g,/\bwent\b/g];
var REPLACEMENTS_TO_POOP = [POOP, "Pooping", "Pooped"];
var P_TAGS = ["h2", "h3", "h4", "h5", "h6", "p"];
POOP 是一个字符串,表示实际的“Poop”(便便)一词,定义为一个伪常量,因为即使便便是生活的绝对常量,JavaScript 也没有规则。
PATTERNS_TO_GO 是一个正则表达式模式数组,每个模式结构相似。‘/\bgo\b/g’。我们首先找到一个单词边界‘\b’,然后是字符‘go’,然后是另一个单词边界‘\b’。全局标志‘g’确保我们在字符串中获取匹配的每一个实例。
REPLACEMENTS_TO_POOP 包含与 PATTERNS_TO_GO 数组中的每个元素对应的术语。这是正则表达式需要替换的每个“匹配”的“替换项”。
P_TAGS 包含一个元素选择器列表,代表非一级标题。就像狗一样,这些是我们想要标记的元素。
3. 简化 DOM 选择
方法 pickOutUnderwearByTag 将返回用于留下标记的 DOM 元素。就像如厕训练一样,我们学会了自己去,而无需 jQuery。
function pickOutUnderwearByTag(tags) {
var underwearSelectors = tags;
var underwearEls = [];
for(var i in underwearSelectors){
var els = Array.prototype.slice.call(document.getElementsByTagName(underwearSelectors[i]));
underwearEls = underwearEls.concat(els);
}
return underwearEls;
}
4. 整合
poopIfYouHaveToGo 循环遍历 PATTERNS_TO_GO 数组中的每个条目,在“内衣”(underwaer)元素中查找匹配项。每个匹配项都会被替换为 REPLACEMENTS_TO_MATCH 中相应的选项。
function poopIfYouHaveToGo(){
//find all paragraph elements
var sourceEls = pickOutUnderwearByTag(P_TAGS);
for(var i = 0; i
var sourceEl = sourceEls[i];
var searchStr = sourceEl.innerHTML;
//identify matches of each form of to go
for(var j = 0; j< PATTERNS_TO_GO.length; j++){
var toGo = PATTERNS_TO_GO[j];
var toPoop = REPLACEMENTS_TO_POOP[j];
searchStr = searchStr.replace(
toGo,
(searchStr.match(/^[A-Z]/)) ?
toPoop :
toPoop.toLowerCase()
);
}
sourceEl.innerHTML = searchStr;
}
}
5. 运行它
我们的第一个 Skidmarklet 任务准备就绪。
!function skidmark(){
poopIfYouHaveToGo();
}();
示例 1 - 这就是我们在页面上留下“污迹”的方法。
第二课
在第二课中,我们将在文本中扩展替换多个单词。在这里,我们不再使用正则表达式列表来查找和替换单个单词,而是使用正则表达式的“或”运算符“|”。
1. 定义一些变量
好的,只有一个变量,一个名为 POOPY_TERMS 的正则表达式,匹配三个单词中的任何一个(loaf、duty 和 business)。
var POOPY_TERMS = /\b(loaf|duty|business)\b/g;
2. 定义方法
运行方法 poopWhereYouSeeIt 会遍历相同的“内衣”(underwear)元素,将任何接近的“turd”(粪便)POOPY_TERM 字面意义上替换为 POOP。
function poopWhereYouSeeIt() {
var sourceEls = pickOutUnderwearByTag(P_TAGS);
for (var i = 0; i< sourceEls.length; i++) {
sourceEls[i].innerHTML = sourceEls[i].innerHTML.replace(
POOPY_TERMS,
POOP
);
}
}
3. 运行它
我怎么看就怎么说,Skidmarklet 也必须 poopWhereYouSeeIt。
!function skidmark(){
poopWhereYouSeeIt();
}();
示例 2 - 这就是我们在页面上留下“污迹”的方法。
第三课
通过我们共同的人类经验,屎找到了一个名字。玉米屎、屁股尿和兔粪,这些只是我想到的几个。便便,就像便便游戏一样,一切都与标题有关,所以让我们把我们的正则表达式括约肌集中起来,从网页的标题区域挤出一些工作。为了给这个页面命名为“poo”,我们正在做一些更危险的事情。
以前我们知道要替换哪些词。现在我们将通过替换页面标题 <title> 和主标题元素 <h1> 中的一个随机选择的单词来实现便便游戏的精髓。在之前的课程中,如果页面不包含我们预选的任何单词,页面上仍然不会有任何便便。但现在,页面无法逃脱,我们知道它最终会被某种方式抹上便便。
1. 定义一些变量
var TEST_CASE = /^[A-Z]/;
var POOP_BOUNDARY = /\b(\S+)\b/g;
var NAME_TAGS = ["title", "h1"];
TEST_CASE 是一个简单的表达式,用于测试以任何大写字母开头的字符串。
POOP_BOUNDARY 匹配被认为是“单词”的内容。在此示例中,一个或多个连续的非空白字符位于单词边界之间。
NAME_TAGS 是我们要匹配的标签数组。你内裤上的地方,你可能会写上你的名字,以免丢失它。
2. 分离可重用实用程序
如果你读过《代码大全》,我不在乎你的意见。我的观点是,如果每个方法只有一个目的,那么代码就更具可读性和可重用性。以下方法封装了共同完成我们目标的各个任务。
function insertPoopHere(str) {
var word = randomWord(str);
return poopInCase(str, word);
}
function poopInCase(str, word) {
return str.replace(
new RegExp('\\b(' + word + ')+\\b'),
word.match(TEST_CASE) ? POOP : POOP.toLowerCase()
);
}
function randomWord(str){
var arr = str.match(POOP_BOUNDARY);
return arr[Math.floor((Math.random()*arr.length))];
}
randomWord - 随机选择一个单词,将其替换为“poop”。
poopInCase - 区分大小写地将单词替换为“poop”。
insertPoopHere - 从值数组中选择一个随机元素。
3. 定义方法
function nameYourPoop() { var sourceEls = pickOutUnderwearByTag(NAME_TAGS); for (var i = 0; i< sourceEls.length; i++) { sourceEls[i].innerHTML = insertPoopHere(sourceEls[i].innerHTML); } }nameYourPoop 从“内衣”(underwear)名称标签中获取所有单词,随机选择一个单词替换为“poop”。我们使用两个正则表达式来实现这一点,POOP_BOUNDARY 用于获取所有符合单词的字符串匹配项,POOP 作为替换项。一旦我们有了所有单词的数组,我们就随机选择一个单词,并将该单词注入一个新的 JavaScript RegExp 对象。这里再次,正则表达式模式将单词本身夹在单词边界之间,所以,如果单词是“with”,我们也不会改变单词“wherewithall”的中间部分。
4. 运行它
!function skidmark(){
nameYourPoop();
}();
示例 3 - 这就是我们在页面上留下“污迹”的方法。
第四课
第三课为我们提供了 insertPoopHere 方法,该方法仅狭义地应用于页面标题元素。在最后一课中,我们将把它发扬光大;我们将替换页面中每个段落的每个句子中的一个单词。为了做到这一点,我们需要先识别一个句子,然后将其“染色”。
1. 定义一个变量
var POOP_SENTENCES = /(\S.+?[.!?])(?=\s+|$)/g;
POOP_SENTENCES 是一个正则表达式模式,用于匹配句子的结构。在我认为称为英语的语言中,句子是可预测的:它们通常以一个“\S”非空白字符开始,后面跟着一堆其他字符和单词,以句号、感叹号或问号结尾,后面跟着空格或换行符。有趣的是,至少有几个是正则表达式中的运算符,但在字符集中,它们被用作字面量。这就是为什么 [.!?] 不需要为每个标点符号加上“/”转义字符。
2. 定义方法
/**
* insert poop where you find p's
*/
function poopAndP(){
var sourceEls = pickOutUnderwearByTag(P_TAGS);
for (var i = 0; i< sourceEls.length; i++) {
var text = sourceEls[i].innerHTML;
var sentences = text.match(POOP_SENTENCES);
if(!sentences)
continue;
for(var j = 0; j<sentences.length; j++)
var sentence = sentences[j];
var poopySentence = insertPoopHere(sentence);
text = text.replace(sentence, poopySentence);
}
}
sourceEls[i].innerHTML = text;
}
一旦我们单独提取出每个句子,我们就可以像在第三课中那样,选择一个随机单词,并将其替换为“poop”。poopAndP 在我们现有的 P_TAGS “内衣”(underwear)元素中正是这样做的。
3. 运行它
/**
* Smear poop on some underwear
*/
!function skidmark(){
poopIfYouHaveToGo();
poopWhereYouSeeIt();
nameYourPoop();
poopAndP();
}();
示例 4 - 这就是我们在页面上留下“污迹”的方法。
结论
就像任何一次成功的如厕活动一样,让我们通过点燃一根火柴来结束,并可能引发一场对话。目的是让教程变得有趣,并在你身上留下印记,所以说出你的想法吧!留下评论或将其“冲”回网络,这取决于你。希望这能让你从典型的教程搜索中获得一丝教育性的消遣。