[草泥马语] ws2gmh之正则版

本文介绍了一种从Whitespace编程语言升级到草泥马语的编译器实现方法,并提供了Java和Ruby两种语言的具体实现示例。
友情支持草泥马语官方网站:[url=http://code.google.com/p/grass-mud-horse/]>>= 猛击这里 =<<[/url]

草泥马语是一种脱胎自[url=http://compsoc.dur.ac.uk/whitespace/]Whitespace[/url]的[b]全新[/b]语言。它是如此的新,我们可以放心的把Whitespace程序[b]升级[/b]为草泥马版。官网提供的发行版里就有ws2gmh工具帮我们完成升级。

在[url=http://grass-mud-horse.googlecode.com/svn/trunk/src/cn/icybear/GrassMudHorse/WS2GMH.java]WS2GMH.java[/url]中,升级的核心逻辑如下:
int ch;
while ((ch = reader.read()) != -1) {
switch (ch) {
case ' ':
// writer.append("[Space]");
ch = '草';
break;
case '\t':
// writer.append("[Tab]");
ch = '泥';
break;
case '\n':
// writer.append("[LF]\n");
writer.append('马');
break;
}
writer.append((char) ch);
}

(注意该程序保留了\n;另外Java I/O的默认处理是读文件的时候把\r\n变成\n)
这是一个while-switch结构。不考虑运行效率,有没有办法写得更精悍一点呢?

先来看JavaScript版本甲:
function ws2gmh(wsSrc) {
return wsSrc.replace(/( )|(\t)|(\n)/mg, function (_, p1, p2, p3) {
return p1 && '草' || p2 && '泥' || p3 && '马\n'
})
}

可以在浏览器里测试:
<html>
<meta http-equiv="Content-Type" content="text/html;charset=GBK" />
<head>
<script type="text/javascript">
function ws2gmh(wsSrc) {
return wsSrc.replace(/( )|(\t)|(\n)/mg, function (_, p1, p2, p3) {
return p1 && '草' || p2 && '泥' || p3 && '马\n'
})
}

function sync() {
var ws_textarea = document.getElementById('ws_textarea')
var gmh_textarea = document.getElementById('gmh_textarea')

// strip the CRs, mimic Java's file I/O behavior
var ws_src = ws_textarea.value.replace(/\r/mg, '')
gmh_textarea.value = ws2gmh(ws_src)
}
</script>
</head>
<body>
<div>
<p>Whitespace:<br />
<textarea id="ws_textarea" cols="80" rows="10" width="100%" onkeyup="sync()"></textarea>
</p>
</div>
<div>
<p>草泥马语:<br />
<textarea id="gmh_textarea" cols="80" rows="10" width="100%" readonly="true" disabled="true"></textarea>
</p>
</div>
</body>
</html>

如果从外部文本编辑器复制过来的话要注意了,有些编辑器会自动转换掉了单个的\n或\r,或\r\n,总之复制进来前注意一下……

然后,JavaScript版本乙:
var mapping = {
' ' : '草',
'\t': '泥',
'\n': '马\n'
}

function ws2gmh(wsSrc) {
return wsSrc.replace(/[ \t\n]/mg, function (s) {
return mapping[s]
})
}

当然mapping直接写在ws2gmh()里也行,只不过要重复求值有点不太爽。要实验的话照样放到前面的HTML里换掉版本甲即可。

用JavaScript能行,用Ruby当然也能。版本甲:
def ws2gmh(ws_src)
ws_src.gsub(/( )|(\t)|(\n)/m) { $1 && '草' || $2 && '泥' || $3 && "马\n" }
end

版本乙:
def ws2gmh(ws_src)
mapping = { ' ' => '草', "\t" => '泥', "\n" => "马\n" }
ws_src.gsub(/[ \t\n]/m) {|s| mapping[s] }
end

版本乙变种:
def ws2gmh(ws_src)
mapping = { ' ' => '草', "\t" => '泥', "\n" => "马\n" }
ws_src.gsub(/[#{Regexp.escape mapping.keys.join}]/m) {|s| mapping[s] }
end

这个变种对mapping的变化敏感度更低些,但运行时开销更大些

于是官方版WS2GMH的完整逻辑就可以用以下脚本实现:
#!/usr/bin/env ruby
# -*- coding: gbk -*-

def ws2gmh(ws_src)
mapping = { ' ' => '草', "\t" => '泥', "\n" => "马\n" }
ws_src.gsub(/[ \t\n]/m) {|s| mapping[s] }
end

if __FILE__ == $0
begin
ws_file, gmh_file = ARGV
raise unless ws_file && File.extname(ws_file) =~ /\.ws/i
gmh_file ||= ws_file[0..-3] + 'gmh'
open(gmh_file, 'wb') {|f| f << ws2gmh(File.read(ws_file)) }
rescue
puts 'Usage: ws2gmh <ws_file> [gmh_file]'
end
end


当然用Java也能实现正则版,只是写起来麻烦……懒得写了。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值