查看文章 |
数年来的探索与学习,我已经得出了一个深刻的结论 —— 处理字符串是一份糟糕的事情,尤其当你使用JavaScript去处理它们的时候。幸运的是,Prototype 框架为String对象贡献了不少让人眼前一亮的新函数,让我们可以工作得轻松一些。听起来有了一个完美的机会可以偷懒了:) -- 让我们开始工作吧! 注意 : 我使用的是 Prototype 1.5 版本中提供的新字符串函数 先让我们创建一个简单的字符串,后面我们会常常操作它来示例: var string = 'Laziness always pays off now.'; String.gsubgsub 方法与JavaScript原生的 replace 方法类似,但它功能更强大。它接受两个参数,第一个是需要搜索的式样(pattern)。它可以是一个简单的字符串或者一个正则表达式。第二个参数则指定式样匹配的部分将被替换成的内容。 我们先从简单开始,我不喜欢空格,所以让我们把空格换成下划线。 string.gsub(' ', '_');
似乎没什么特别的,我们也可以直接用 string.replace(/\s/g, '_') 来完成类似的事情。不过当你意识到 gsub 的第二个参数可以是一个函数的时候就会发现 gsub 的发光点了。该函数对字符串中每个被匹配的部分都将执行一次。它接受式样匹配后的 matches 数组(译者著: JavaScript 的String.match() 方法返回的数组)作为参数,接下来你就返回一个被处理过后的字符串。听起来有点迷糊?看代码吧: string.gsub(/\s\w/, function(match){ return match[0].toUpperCase(); });
字符串中每个匹配的部分都传递给参数函数,该函数处理被匹配的部分并返回替换后的版本。我们需要用 match[0] 来引用 match 对象是因为正则表达式的匹配结果是作为一个数组返回的。 数组中索引为0的值就是整个匹配的内容,从第二个值开始则对应正则表达式中每个圆括号定义的组(group)的匹配内容(译者著:如果看不懂,请参阅正则表达式相关资料)。如果我们在正则表达式中使用了分组,那么我们就能从 matches 数组中获取这些元素。 string.gsub(/(s|f)(\s)/, function(match){ return match[1].toUpperCase() + '-' + match[2]; });
String.subString.sub 同 String.gsub 几乎一样,但它能再多接受一个可选的参数。与gsub默认替换字符串中全部匹配的内容不同,sub 只替换由第三个参数指定个数的匹配内容(默认是1个)。让我们看原来的例子: string.sub(' ', '_');
这一次,只有第一个匹配的空格被替换掉,如果我们传入第三个参数再运行下面的例子,我们就可以看到不同了: string.sub(' ', '_', 3);
其他方面,String.sub 和 String.gsub 一样。(译者著:可见 gsub 比 sub 多出来的 g 也就代表着正则表达式里的 g 标记,该标记设定全文查找出现的所有 pattern)。 String.scanscan 方法就是简单的调用 gsub,传入式样和一个枚举函数作为参数,该枚举函数对匹配的内容循环执行。 string.scan(/\w+/, alert); 另一个用法,就是可以用 scan 来获取将所有匹配结果的数组。 var results = [];
string.scan(/\w+/, function(match){ results.push(match[0].toUpperCase()); });
String.truncate这个方法的用途正如你看名字后所期望的那样,但有一些小机关(就我看来),truncate 由第一个参数指定的数目来截断字符串, string.truncate(15); 似乎工作正常,不过它只得到了12个字符而不是我们期望的15个。这是因为它还有一个可选的第二个字符类型参数,该参数将附在截断的字符串之后,并且也参与返回长度的计数。第二个参数默认是"...",做如下的修改就可以满足我上面例子所希望得到的结果: string.truncate(15, ''); 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'});
数组它也支持: var arrayTemplate = new Template('Original: #{0}, Sequel: #{1}');
arrayTemplate.evaluate(['Naked Gun', '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>'});
如果你需要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}_');
使用模板字符串相比于使用一个函数做为作为第二个参数,变量匹配的索引与传递给函数的matches数组索引是对应的。这有一个例子: 'Cory Hudson'.gsub(/(\w+) (\w+)/, '#{2}, #{1}');
注意此时模板式样不能象直接通过构造器创建Template对象那样支持定义式样语法。你只能使用Ruby的语法,不过这用起来也不坏,不是吗? 译者著: 'Cory Hudson'.replace(/(\w+) (\w+)/g, "$2, $1"); 所以支持函数参数才是 gsub 强大之处。 Strings Can Be Fun!使用Prototype给原生String对象提供的方法真是颇有趣味,它们能节省你不少编码时间,而事实上,变幻的参数使得它们是如此灵活。 |