惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
Y
Y Combinator Blog
Recorded Future
Recorded Future
博客园 - Franky
I
InfoQ
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
Cyberwarzone
Cyberwarzone
The Register - Security
The Register - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
Cloudbric
Cloudbric
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
F
Full Disclosure
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Check Point Blog
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
U
Unit 42
N
Netflix TechBlog - Medium
The Cloudflare Blog
Spread Privacy
Spread Privacy
Microsoft Azure Blog
Microsoft Azure Blog
美团技术团队
T
Troy Hunt's Blog
Engineering at Meta
Engineering at Meta
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tenable Blog
B
Blog
S
Securelist
H
Hacker News: Front Page
Google Online Security Blog
Google Online Security Blog
G
Google Developers Blog

博客园 - Tachikoma

用Ruby实现 Web Service Server ,并用Ruby发送 HTTP请求 Web Service Android 使用 Ksoap2 出现的低级错误... - Tachikoma Cygwin中通过RJB在Ruby下调用ICTCLAS(JAVA) ICTCLAS4J 的编译脚本 Ruby Sandbox 实现运行客户代码 - Tachikoma Ruby在使用MongoDB时,对Cursor的重新包装 ruby 下使用 ICTCLAS(JAVA) RJB 在windows下的一些安装事项 Ruby手工测试正确,rcov测试失败的解决 在dell dimension 5150 上安装 leopard 手记 Rails测试中清空数据表/载入空fixtures RDoc 解决同名module 与 Class的问题 C 实用的 e-editor 的bundle Best of Ruby Quiz - Animal Quiz Best of Ruby Quiz - MadLib - Tachikoma 使用selenium-on-rails的一些讨论 3]assertXpathCount的使用 使用selenium-on-rails的一些讨论 2]清理缓存 - Tachikoma - 博客园 使用selenium-on-rails的一些讨论 [0,1] 关于 rails ActiveRecord 属性 以及 foreign_key 不直接用数据库项目 时的一些讨论
Best of Ruby Quiz - GEDCOM Parser
Tachikoma · 2008-07-23 · via 博客园 - Tachikoma

[0] 首先,分析书后源代码,整题建立在下面的假设上:Level 标号从0开始,依次递增,且递增跨度为1,输入不存在错误

也正是这一点假设,LEVEL值可以不作为结点属性处理,即LEVEL值实际上是节点在堆栈中位置的代表,用堆栈结构可以轻松化解LEVEL带来的麻烦

[1] 第一种想法是用REXML,将字符串解析后存入XML结构,最后统一输出,源代码和书上一样

require 'rexml/document'
doc 
= REXML::Document.new '<gedcom/>'
stack 
= [doc.root]
IO.read(ARGV[
0]).each do |line|
  next 
if line =~ /^\s*$/
  line 
=~ /^\s*(\d+)\s+(@\S+@|\S+)\s*(.*?)$/ or raise "Invalid GEDCOM"
  level , tag , data 
= $1.to_i , $2 , $3
  stack.pop 
while (level + 1 < stack.size)
  parent 
= stack.last
  
if tag =~ /^@(\S+)@$/
    ele 
= parent.add_element data
    ele.attributes[
'id'= tag
  
else
    ele 
= parent.add_element tag
    ele.text 
= data
  end
  stack.push ele
end
File.open(
"output_std.txt","w"do |file|
  doc.write(file,
0)
end

 [2] 当数据规模很大时,不可能将所有数据存入XML结构内存,再统一输出,So fight and run

class Node
  def initialize(tag_or_id,data 
= "")
    
if tag_or_id =~ /@.*@/
      @name , @myid , @value 
= data , tag_or_id , ""
    
else
      @name , @value ,@myid 
= tag_or_id , data , ""
    end
  end
  
  def to_s_first
    s 
= @myid.empty? ? "<#{@name}>\n" : "<#{@name} id=\"#{@myid}\">\n" 
    s 
+= (@value+"\n") unless @value.empty?
    s
  end
  
  def to_s_last
    
"</#{@name}>\n"
  end
  
end

stack 
= [Node.new "gedcom"]
File.open(
"output.txt","w"do |file|
  file.print stack.first.to_s_first
  IO.read($
*[0]).each do |line|
    next 
if line =~ /^\s*$/
    line 
=~ /^\s*(\d+)\s+(@\S+@|\S+)\s*(.*?)$/ or raise "error"
    level , tag_or_id , data 
= $1.to_i , $2 , $3
    file.print stack.pop.to_s_last 
while (level + 1 < stack.size)
    node 
= Node.new(tag_or_id,data)
    file.print node.to_s_first
    stack.push node  
  end
  file.print stack.first.to_s_last
end

将节点打包成类,第二步解析交给类构造去做,输出也交给类做

在入栈时输出第一部分,在出栈时输出第二部分

自然想到将栈也打包

 1require 'rexml/text'
 2
 3class Node
 4  def initialize(tag_or_id,data = "")
 5    if tag_or_id =~ /@.*@/
 6      @name , @myid , @value = data , tag_or_id , ""
 7    else
 8      @name , @value ,@myid = tag_or_id , data , ""
 9    end
10  end
11  
12  def to_s_first
13    s = @myid.empty? ? "<#{@name}>\n" : "<#{@name} id=\'#{@myid}\'>\n" 
14    s += (@value+"\n") unless @value.empty?
15    s
16  end
17  
18  def to_s_last
19    "</#{@name}>\n"
20  end
21  
22end
23
24class Stack < Array
25    def push(obj)
26        raise "type error" unless obj.is_a? Node
27        print obj.to_s_first        
28        super(obj)
29    end
30    
31    def pop
32        print self.last.to_s_last
33        super
34    end
35end
36
37def file_write_env(file)
38    $stdout =     file
39    yield
40    $stdout = STDOUT
41end
42
43stack = Stack.new
44File.open("output.txt","w"do |file|
45    file_write_env(file) do
46        stack.push(Node.new "gedcom")
47          IO.read($*[0]).each do |line|
48            next if line =~ /^\s*$/
49            line =~ /^\s*(\d+)\s+(@\S+@|\S+)\s*(.*?)$/ or raise "error"
50            level , tag_or_id , data = $1.to_i , $2 , REXML::Text::normalize($3)
51            stack.pop while (level + 1 < stack.size)
52            stack.push Node.new(tag_or_id,data)  
53          end
54        stack.pop
55    end
56end

第50行调用  REXML::Text::normalize 将字符串escaping ,达到和XML输出差不多的效果,完成字符转义

[PS] 有一点不很明白,用REXML构造法得到的输出,和最后的方法得到的输出在空格处理上有一定差异,REXML对于多空格只输出一个,而最后两种方法忠实于输入