我正在寻找一种从Perl中解析真正的
JavaScript对象数据(由于多种原因,不符合JSON标准)的方法.
我发现JSON
模块,如果启用了allow_singlequote和allow_barekey选项,则可以正常工作,但我仍然无法解析包含转义单引号和未转义双引号的单引号值.例如,
{ label : 'can\'t process' }
和
{ label : '"bad" character' }
扔
illegal backslash escape sequence in string
和
invalid character encountered while parsing JSON string
因为模块只需要转义标准字符集,无论包含引号如何.
我以为我找到了一些可以在JSON::DWIW
模块中使用的东西,但它自2010年以来一直没有更新,我无法安装它.
到目前为止,我唯一的答案是使用JavaScript
安装一个完整的JavaScript引擎,并将该字符串作为JavaScript代码运行.这样做很好,但远非直截了当,对我想要的东西来说太过分了.
有没有人对我可以尝试的替代品有任何建议?
最佳答案 有很多JSON模块在CPAN上敲响了,其中很多都有宽容模式.但是,似乎没有人能够处理这种特殊情况. (我认为
JSONY可能,但遗憾的是没有.但是,我想如果你报告这个案例,作者可能会热衷于让它发挥作用.)
我的快速和肮脏的建议是采用现有的纯Perl JSON模块,并破解它以使其工作. JSON::Tiny是一个很好的候选人. CPAN上最新的JSON :: Tiny版本的以下补丁似乎可以解决您提供的两个简短示例:
--- Tiny.orig 2014-02-22 22:17:50.923272286 +0000
+++ Tiny.pm 2014-02-22 22:18:23.847435546 +0000
@@ -160,11 +160,13 @@
until (m/\G$WHITESPACE_RE\}/gc) {
# Quote
- m/\G$WHITESPACE_RE"/gc
+ m/\G$WHITESPACE_RE(["']|[^\W0-9]\w+)/gc
or _exception('Expected string while parsing object');
# Key
- my $key = _decode_string();
+ my $key = ($1 =~ /['"]/)
+ ? _decode_string()
+ : $1;
# Colon
m/\G$WHITESPACE_RE:/gc
@@ -187,13 +189,14 @@
}
sub _decode_string {
+ my $quote = shift;
my $pos = pos;
# Extract string with escaped characters
- m!\G((?:(?:[^\x00-\x1f\\"]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})){0,32766})*)!gc; # segfault on 5.8.x in t/20-mojo-json.t #83
+ m!\G((?:(?:[^\x00-\x1f\\$quote]|\\(?:[$quote\\/bfnrt]|u[0-9a-fA-F]{4})){0,32766})*)!gc; # segfault on 5.8.x in t/20-mojo-json.t #83
my $str = $1;
# Invalid character
- unless (m/\G"/gc) {
+ unless (m/\G$quote/gc) {
_exception('Unexpected character or invalid escape while parsing string')
if m/\G[\x00-\x1f\\]/;
_exception('Unterminated string');
@@ -247,7 +250,8 @@
m/\G$WHITESPACE_RE/gc;
# String
- return _decode_string() if m/\G"/gc;
+ return _decode_string(q["]) if m/\G"/gc;
+ return _decode_string(q[']) if m/\G'/gc;
# Array
return _decode_array() if m/\G\[/gc;
@@ -268,6 +272,9 @@
# Null
return undef if m/\Gnull/gc; ## no critic (return)
+ # Bareword string
+ return $1 if m/\G([^\W0-9]\w+)/gc;
+
# Invalid character
_exception('Expected string, array, object, number, boolean or null');
}