-
Notifications
You must be signed in to change notification settings - Fork 2
问题正文标准录入格式
ben7th edited this page Jan 16, 2014
·
9 revisions
服务端持久化存储中(目前使用MongoDB)保存着所有的问题数据。
问题正文是问题数据的组成部分(另外一部分是问题选项),具有以下特征:
- 问题正文由图片,代码段,普通文本组成。“图片”,“代码段”,“普通文本”被称为不同的“内容类型”。将来还有可能扩展其他的内容类型,例如内嵌音频,内嵌视频,录音控件,二维条码扫描控件等。
- 不同的“内容类型”在问题正文内按照一维数组方式排列。目前没有排版信息描述。
- 问题正文在录入时,为方便录入者,需要遵循标准格式规定,保存在持久化存储中,再由
question.make_content
整理为问题正文标准JSON格式,以供客户端使用。
text:
请看以下代码段,再根据要求回答问题:
code:javascript:
var a = 'Hello';
var b = 'World';
var c = a + ' ' + b;
console.log(a, b, c);
text:
请问以下图片
image:
http://ww2.sinaimg.cn/bmiddle/548cebedjw1eca640hqlhj20h50bqq6k.jpg
text:
是否代表了这段代码正确的输出结果?
一段标准录入格式问题文本,每种内容类型段落以类型标识开始,以空行后的下一个类型标识,或EOF结束。
text:
image:
code:
被称为类型标识。目前只有这三种。
text:
我是普通文本。到这里不算结束。
普通文本就是我。到这里才结束,因为后面有下一个类型标识。
text:
对不起,第二个类型标识还是文本
image:
http://ww2.sinaimg.cn/bmiddle/548cebedjw1eca640hqlhj20h50bqq6k.jpg
以上正文应该被解析成三个类型段落。
其中第一个类型段落中包含空行,但中间的空行并不是这个类型段落的结束。因为后面没有出现新的类型标识。
直到遇到空行紧接着一个类型标识时,才认为这段文本结束了。因此,第一段文本被解析为:
我是普通文本。到这里不算结束。
普通文本就是我。到这里才结束,因为后面有下一个类型标识。
后面紧跟着图片的url(包含 http:// https:// 部分)。否则就是不合法的。
image:
http://ww2.sinaimg.cn/bmiddle/548cebedjw1eca640hqlhj20h50bqq6k.jpg
和普通文本一样,中间的空行不被视作结束。
有时候,文本中本身就包含 text: image: 等字符串,但是又不想被识别为类型标识。则使用转义方法。
text:
我是第一行
raw:text:
这里声明了转义。不是新段落。
text:
这里才是新段落。
以 raw:在行首作为转义。以上文本将被识别为:
我是第一行
text:
这里声明了转义。不是新段落。
这里才是新段落。
两个段落。
将标准录入格式解析成问题正文标准JSON格式的脚本如下:
class QuestionContentParser
def initialize(content)
@content = content
end
def output
@line_num = 0
@token = nil
@output = []
@lines_stack = []
@code_lang = ''
lines = @content.lines
@lc = lines.length
lines.each do |line|
@line_num += 1
s = line.strip
case @token
when nil
deal_nil(s)
when 'image:'
deal_image(s)
when 'text:'
deal_text(s)
when 'code:'
deal_code(s)
end
end
@output
end
def is_token(s)
return 'image:' if s == 'image:'
return 'text:' if s == 'text:'
if m = s.match(/code\:(.+)\:/)
@code_lang = m[1]
return 'code:'
end
return nil
end
def deal_nil(s)
return if s == ''
it = is_token(s)
if it
@token = s
@lines_stack = []
end
# raise "第#{line_num}行:无法找到合理的段落类型标识"
end
def deal_image(s)
url = s
@output << {
:type => :image,
:data => {
:url => url
}
}
@token = nil
@lines_stack = []
end
def deal_text(s)
if _is_end_of_block?(s)
@output << {
:type => :text,
:data => {
:content => pack_lines_stack
}
}
@token = is_token(s)
@lines_stack = []
return
end
@lines_stack << s
end
def deal_code(s)
if _is_end_of_block?(s)
@output << {
:type => :code,
:data => {
:lang => @code_lang,
:content => QuestionCodeFormatter.new(pack_lines_stack, @code_lang).get_content
}
}
@token = is_token(s)
return
end
@lines_stack << s
end
def pack_lines_stack
str = @lines_stack.map { |x|
x.sub /^raw\:/, ''
}[0..-2] * "\n"
@lines_stack = []
return str
end
def _is_end_of_block?(s)
return true if is_token(s) && @lines_stack.last == ''
if @line_num == @lc
@lines_stack << s
@lines_stack << ''
return true
end
return false
end
end
使用方法:
QuestionContentParser.new(content).output
范例:以下字符串:
text:
我是普通文本。到这里不算结束。
普通文本就是我。到这里才结束,因为后面有下一个类型标识。
text:
对不起,第二个类型标识还是文本
code:javascript:
var a = 'Hello';
var b = 'World';
var c = a + ' ' + b;
console.log(a, b, c);
text:
raw:image:
haha
image:
http://ww2.sinaimg.cn/bmiddle/548cebedjw1eca640hqlhj20h50bqq6k.jpg
通过以上脚本处理将被解析为:
{:type=>:text, :data=>{:content=>"我是普通文本。到这里不算结束。\n\n普通文本就是我。到这里才结束,因为后面有下一个类型标识。"}}
{:type=>:text, :data=>{:content=>"对不起,第二个类型标识还是文本"}}
{:type=>:code, :data=>{:lang=>"javascript", :content=>[["keyword", "var"], ["space", " "], ["ident", "a"], ["space", " "], ["operator", "="], ["space", " "], ["delimiter", "'", "string"], ["content", "Hello", "string"], ["delimiter", "'", "string"], ["operator", ";"], ["space", "\n"], ["keyword", "var"], ["space", " "], ["ident", "b"], ["space", " "], ["operator", "="], ["space", " "], ["delimiter", "'", "string"], ["content", "World", "string"], ["delimiter", "'", "string"], ["operator", ";"], ["space", "\n"], ["keyword", "var"], ["space", " "], ["ident", "c"], ["space", " "], ["operator", "="], ["space", " "], ["ident", "a"], ["space", " "], ["operator", "+"], ["space", " "], ["delimiter", "'", "string"], ["content", " ", "string"], ["delimiter", "'", "string"], ["space", " "], ["operator", "+"], ["space", " "], ["ident", "b"], ["operator", ";"], ["space", "\n\n"], ["ident", "console"], ["operator", "."], ["ident", "log"], ["operator", "("], ["ident", "a"], ["operator", ","], ["space", " "], ["ident", "b"], ["operator", ","], ["space", " "], ["ident", "c"], ["operator", ")"], ["operator", ";"]]}}
{:type=>:text, :data=>{:content=>"image:\nhaha"}}
{:type=>:image, :data=>{:url=>"http://ww2.sinaimg.cn/bmiddle/548cebedjw1eca640hqlhj20h50bqq6k.jpg"}}