textfsm 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b759f267290748811b004b57362a3a4879aa13b6b50e72e19169c0882cec643d
4
- data.tar.gz: fab42a0d8bd58f0301083f8b69d02b00f8861c05b909caa45fb8ad87b62ef247
3
+ metadata.gz: e4032e879606f9930b18496dc11d5ee391891ebc206d3a18ff7ad8bac909c881
4
+ data.tar.gz: dc4767adf5127b8a799ec83498d18bf6f065ad85f8ee3e88f465eb4057fbb548
5
5
  SHA512:
6
- metadata.gz: 5a3eff19383f13ed24be4b2ddd6298e3c2900e5db39c2bd2c030b6e4af88580775efa61ba383abdff0eeb6b4685eb599a5c5bc12fbafe3fd564a147f65d4b90f
7
- data.tar.gz: e3e32ea40133743f8f72604abd7ded7361aa0add174639494338562e488df041dd0e10f6983c67217907702096a9e3adcd2e12b6b4c761d6348bcf65875202b3
6
+ metadata.gz: 0170443b06fb0b0e0d564b23b5fa386a868fddffccb03360d38be2b88425224a308e379d2416a39b886e50f3ae8a4010808d8c816fe15d9c0b990a92e3266c15
7
+ data.tar.gz: 19c0e4375e5f4a12e820feb36cfe220ae0f9ca75b255b800e47fe11817e066cc555b0b39afc2f9bc2135b1250bbe30b4a15996b72d8bbefa5fb7fce7d7c2239c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.4.1(2026-10-08)
4
+
5
+ - 修复多行正则中 `^` 漏匹配末尾换行后空行的问题,保留嵌套标志与命名捕获语义。
6
+ - 加快含重复模式的索引加载,保持编译回调的执行顺序和首条匹配规则。
7
+ - 减少逐行解析的临时字符串,保留 Unicode 分隔符、空行和终止状态语义。
8
+
3
9
  ## 0.4.0(2026-10-07)
4
10
 
5
11
  - 加速多行 `Fillup` 回填,复用冻结值和预计算的可见列位置,保留历史快照与可修改导出的数据隔离。
data/README.md CHANGED
@@ -31,7 +31,7 @@ gem "textfsm", path: "/path/to/textfsm"
31
31
  ```sh
32
32
  bundle install
33
33
  bundle exec rake build
34
- gem install ./pkg/textfsm-0.4.0.gem
34
+ gem install ./pkg/textfsm-0.4.1.gem
35
35
  ```
36
36
 
37
37
  源码仓库:[gatework/textfsm](https://github.com/gatework/textfsm)。
@@ -185,6 +185,8 @@ cisco_version_template, Cisco, sh[[ow]] ve[[rsion]]
185
185
 
186
186
  每次查询按需将参与匹配的属性值转换为字符串,并在本次扫描中复用;未知属性和仅遇到通配条件的值不会触发转换。Symbol 与同名 String 属性分别参与匹配,传入的属性集合不会被修改。
187
187
 
188
+ 加载索引时,相同模式在当前索引内只编译一次;`IndexTable` 的 `transform:` 和 `compile:` 回调仍按文件顺序逐单元格执行,回调返回值不会被原地修改。
189
+
188
190
  可绕过 index 显式传入模板:
189
191
 
190
192
  ```ruby
@@ -260,7 +262,7 @@ parser = TextFSM::Parser.new(template, options: { "Uppercase" => Uppercase })
260
262
  工作流验证并上传同次 CI 的 gem,再核对 RubyGems 下载和 GitHub Release 的 SHA256。
261
263
  流程、账号绑定及失败恢复见 [发布说明](docs/RELEASING.md)。
262
264
 
263
- 本地预检可执行 `bundle exec ruby script/release.rb --dry-run --artifact pkg/textfsm-0.4.0.gem`;
265
+ 本地预检可执行 `bundle exec ruby script/release.rb --dry-run --artifact pkg/textfsm-0.4.1.gem`;
264
266
  已有产物路径不会重新构建。更新版本及 CHANGELOG、提交并确认远端 CI 后推送对应版本标签。
265
267
 
266
268
  ## 兼容范围与验证
@@ -269,6 +271,8 @@ parser = TextFSM::Parser.new(template, options: { "Uppercase" => Uppercase })
269
271
 
270
272
  Ruby 使用 Onigmo 正则引擎。本项目转换 Python 命名组 `(?P<name>...)`、命名与数字反向引用、贪婪/懒惰/占有量词、常用内联标志 `i/m/s/x/a/u`、Unicode 字符类及锚点语义。**这不是完整 Python `re` 引擎的替代实现**:Unicode 名称转义 `\N{...}`、条件组等不支持的扩展会报 `TemplateError`;两种引擎的大小写折叠、复杂后行断言等细节仍可能不同。使用额外模板库时,应以实际模板与输入执行对照测试。
271
273
 
274
+ 多行模式的 `^` 匹配输入开头或换行后的位置,包括末尾换行后的空行。可匹配空串的重复组仍可能有不同的回溯结果,例如 `(?:\ba?){2}` 在 `"aa"` 上的匹配长度与 Python 不同;依赖这类行为的模板需单独对照验证。
275
+
272
276
  直接使用 `Pattern` 时,`named_captures(match)` 返回命名捕获的 Hash;`each_capture(match)` 按定义顺序逐项产出名称和值,保留未匹配组的 `nil`,无块时返回 Enumerator。Parser 使用逐项迭代传递字段值,避免为每条匹配规则构造临时 Hash。
273
277
 
274
278
  模板字符串须使用有效且兼容 ASCII 的编码,模板文件和索引文件按 UTF-8 读取。模板或正则的无效编码报告 `TemplateError`,索引的无效编码报告带路径与行号的 `IndexError`;`CliTable` 保留此前成功解析的数据和索引。
@@ -22,12 +22,7 @@ module TextFSM
22
22
 
23
23
  def initialize(path, transform: nil, compile: nil)
24
24
  @header, @rows = Data.copy(read_table(path, transform), immutable: true)
25
- @patterns = @rows.map do |row|
26
- row.to_h do |key, value|
27
- value = compile.call(key, value) if compile
28
- [key, value.nil? || value.empty? ? nil : Pattern.new(value)]
29
- end.freeze
30
- end.freeze
25
+ @patterns = compile_patterns(compile)
31
26
  freeze
32
27
  rescue TemplateError => e
33
28
  raise IndexError, "#{path}: #{e.message}"
@@ -69,6 +64,17 @@ module TextFSM
69
64
 
70
65
  private
71
66
 
67
+ def compile_patterns(compile)
68
+ # 仅在本次构建中共享不可变模式;回调仍逐单元格执行,缓存不跨索引保留。
69
+ compiled = {}
70
+ @rows.map do |row|
71
+ row.to_h do |key, value|
72
+ value = compile.call(key, value) if compile
73
+ [key, value.nil? || value.empty? ? nil : (compiled[value] ||= Pattern.new(value))]
74
+ end.freeze
75
+ end.freeze
76
+ end
77
+
72
78
  def read_table(path, transform)
73
79
  lines = File.foreach(path, encoding: "UTF-8")
74
80
  header = nil
@@ -124,11 +124,10 @@ module TextFSM
124
124
  text = text.read if text.respond_to?(:read)
125
125
  raise ArgumentError, "text must be a String or readable IO" unless text.is_a?(String)
126
126
 
127
- # StringScanner advances by bytes, including for multibyte input, without
128
- # allocating all lines or repeatedly finding character offsets.
127
+ # scan_until 返回新字符串;chop! 原地移除一个分隔字符或整对 CRLF。
129
128
  scanner = StringScanner.new(text)
130
129
  while (line = scanner.scan_until(LINE_SEPARATOR))
131
- process_line(line.byteslice(0, line.bytesize - scanner.matched_size))
130
+ process_line(line.chop!)
132
131
  break if terminal?
133
132
  end
134
133
  process_line(scanner.rest) unless terminal? || scanner.eos?
@@ -109,7 +109,8 @@ module TextFSM
109
109
  end
110
110
 
111
111
  def anchor(character)
112
- return character if @flags[:multiline]
112
+ # Ruby 的 ^ 不匹配末尾换行后的空行,需显式保留 Python 的起始位置。
113
+ return character == "^" ? "(?:\\A|(?<=\\n))" : "$" if @flags[:multiline]
113
114
 
114
115
  character == "^" ? "\\A" : "\\Z"
115
116
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TextFSM
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textfsm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - TextFSM Ruby contributors