Prototype的新字符串函数

< DOCTYPE html PUBLIC -WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml-strictdtd>

先让我们创建一个简单的字符串,后面我们会常常操作它来示例:

var string = 'Laziness always pays off now.';
String.gsub
gsub 方法与JavaScript原生的 replace 方法类似,但它功能更强大。它接受两个参数,第一个是需要搜索的式样(pattern)。它可以是一个简单的字符串或者一个正则表达式。第二个参数则指定式样匹配的部分将被替换成的内容。

我们先从简单开始,我不喜欢空格,所以让我们把空格换成下划线。

string.gsub(' ', '_');// Returns "Laziness_always_pays_off_now."
似乎没什么特别的,我们也可以直接用 string.replace(/\s/g, '_') 来完成类似的事情。不过当你意识到 gsub 的第二个参数可以是一个函数的时候就会发现 gsub 的发光点了。该函数对字符串中每个被匹配的部分都将执行一次。它接受式样匹配后的 matches 数组(译者著: JavaScript 的String.match() 方法返回的数组)作为参数,接下来你就返回一个被处理过后的字符串。听起来有点迷糊?看代码吧:

string.gsub(/\s\w/, function(match){ return match[0].toUpperCase(); });// Returns "Laziness Always Pays Off Now."
字符串中每个匹配的部分都传递给参数函数,该函数处理被匹配的部分并返回替换后的版本。我们需要用 match[0] 来引用 match 对象是因为正则表达式的匹配结果是作为一个数组返回的。 数组中索引为0的值就是整个匹配的内容,从第二个值开始则对应正则表达式中每个圆括号定义的组(group)的匹配内容(译者著:如果看不懂,请参阅正则表达式相关资料)。如果我们在正则表达式中使用了分组,那么我们就能从 matches 数组中获取这些元素。

string.gsub(/(s|f)(\s)/, function(match){ return match[1].toUpperCase() + '-' + match[2]; });// Returns "LazinesS- alwayS- payS- ofF- now."
String.sub
String.sub 同 String.gsub 几乎一样,但它能再多接受一个可选的参数。与gsub默认替换字符串中全部匹配的内容不同,sub 只替换由第三个参数指定个数的匹配内容(默认是1个)。让我们看原来的例子:

string.sub(' ', '_');// Returns "Laziness_always pays off now."
这一次,只有第一个匹配的空格被替换掉,如果我们传入第三个参数再运行下面的例子,我们就可以看到不同了:

string.sub(' ', '_', 3);// Returns "Laziness_always_pays_off now."
其他方面,String.sub 和 String.gsub 一样。(译者著:可见 gsub 比 sub 多出来的 g 也就代表着正则表达式里的 g 标记,该标记设定全文查找出现的所有 pattern)。

String.scan
scan 方法就是简单的调用 gsub,传入式样和一个枚举函数作为参数,该枚举函数对匹配的内容循环执行。

string.scan(/\w+/, alert);// Produces 5 alerts: "Laziness", "always", "pays", "off", "now"
另一个用法,就是可以用 scan 来获取将所有匹配结果的数组。

var results = [];
string.scan(/\w+/, function(match){ results.push(match[0].toUpperCase()); });// results = ['LAZINESS', 'ALWAYS', 'PAYS', 'OFF', 'NOW']
String.truncate
这个方法的用途正如你看名字后所期望的那样,但有一些小机关(就我看来),truncate 由第一个参数指定的数目来截断字符串,

string.truncate(15);// Returns "Laziness alw..."
似乎工作正常,不过它只得到了12个字符而不是我们期望的15个。这是因为它还有一个可选的第二个字符类型参数,该参数将附在截断的字符串之后,并且也参与返回长度的计数。第二个参数默认是"...",做如下的修改就可以满足我上面例子所希望得到的结果:

string.truncate(15, '');// Returns "Laziness always"
Template Class
最后,我们来谈 Template 类,我认为它是一个漂亮的工作。它能让我们构造一个字符串模板,其中设定的变量可以在随后的代码中进行替换。很象 PHP 的模板或者任何我们见过的服务端模板技术。默认的变量替换式样是:#{variable_name}。 这里有一个例子,展示如何创建一个模板:

var linkTemplate = new Template('<a href="#{href}">#{text}</a>');
你可以随后调用它的 evaluate 方法,并传入一个属性名与变量相互对应的对象参数来渲染结果,如下:

linkTemplate.evaluate({href: 'http://www.google.com', text: 'The omnipotent one'});// Returns "<a href=" omnipotent one</a>"
数组它也支持:

var arrayTemplate = new Template('Original: #{0}, Sequel: #{1}');
arrayTemplate.evaluate(['Naked Gun', 'Naked Gun 2 1/2']);// Returns "Original: Naked Gun, Sequel: Naked Gun 2 1/2"
Customizing the Template Variable Pattern
足够的灵活性,让我们可以更深入的来定制自己的 Template 类。比如你已经拥有了一个优秀的模板,但它是用PHP的short tag 语法编写的。你做为一个懒惰的程序员,自然不愿意再重写模板。不过不用担心,付出一些努力对以后的逍遥是值得的。

Template 类构造器第二个可选参数正是一个定义变量替换式样的正则表达式。默认值是常量Template.Pattern,其定义了很不错的#{variable} 语法。而我们也可以定制自己的变量替换语法,试一下下面的代码:

Template.PhpPattern = /(^|.|\r|\n)(<\?=\s*\$(.*?)\s*\?>)/;
现在,我们可以直接应用 PHP 模板了,Prototype 魔术般的让它工作了。

var phpTemplate = new Template('<div id="<?= $id ?>" class="<?= $class ?>"><?= $content ?></div>', Template.PhpPattern);
phpTemplate.evaluate({id: 'news', class: ['updated', 'arbitrary'].join(' '), content: '<p>No news is good news...</p>'});// Returns "<div id="news" class="updated arbitrary"><p>No news is good news...</p></div>"
如果你需要Ajax调用并返回JSON数据,那么这将对你很有帮助。你可以将页面加载的PHP模板创建为一个模板对象,随后执行template的evalute方法并传入Ajax请求得到的JSON对象作为参数。

当然,只有在PHP模板中不包含可能带有隐患的业务/应用逻辑的时候,才建议这样用。记住JavaScript可以访问的任何信息也能被任何人看到。我建议你只在简单变量替换的需求中使用它。如果你大量使用,就要小心点了。

尽管我个人喜爱PHP模板语法,我还是给出一个 Smarty 式样来补充说明:

Template.SmartyPattern = /(^|.|\r|\n)({\$(.*?)\})/;
需要注意的一点就是,自定义的式样必须符合 Template.Pattern 的正则表达式结构(译者著:圆括号的数量与嵌套位置)。如果结构不是按照(beforePattern)(varSyntax(varName)) 的格式,模板中的变量也许就不会被正确替换,因为它依赖于该格式产生对应的1, 2, 3 索引。

Coming Full Circle
现在,已经给大家展示了 Template 类,最后画龙点睛给大家再秀一个String.gsub 和 String.sub 的小技巧,它们的第二个参数其实也可以是一个 Template 模板字符串:

string.gsub(/\s/, '#{0}_');// Returns "Laziness _always _pays _off _now."
使用模板字符串相比于使用一个函数做为作为第二个参数,变量匹配的索引与传递给函数的matches数组索引是对应的。这有一个例子:

'Cory Hudson'.gsub(/(\w+) (\w+)/, '#{2}, #{1}');// Returns "Hudson, Cory"
注意此时模板式样不能象直接通过构造器创建Template对象那样支持定义式样语法。你只能使用Ruby的语法,不过这用起来也不坏,不是吗?

译者著:
其实这样的功能也可以用原生的replace方法来实现,比如:

'Cory Hudson'.replace(/(\w+) (\w+)/g, "$2, $1");
所以支持函数参数才是 gsub 强大之处。

Strings Can Be Fun!
使用Prototype给原生String对象提供的方法真是颇有趣味,它们能节省你不少编码时间,而事实上,变幻的参数使得它们是如此灵活。

posted @ 2007-08-17 11:55  netcorner  阅读(121)  评论(0编辑  收藏  举报