xlg 0.4.2
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 +7 -0
- data/LICENSE +8 -0
- data/README.md +136 -0
- data/bin/xlg +78 -0
- data/lib/cell_matcher.rb +22 -0
- data/lib/excel_grep.rb +62 -0
- data/lib/multi_file_searcher.rb +68 -0
- data/lib/output_formatter.rb +5 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 487577ad7b07e1220696b70de189c3c098a39547c84dc8db0204b5420c4ae0af
|
4
|
+
data.tar.gz: 8e58a4ba07793fd06036bbeb3c03069938dab6fe5f3eb0aa21dc38a7d94912bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 54c70a935c0b50d11d63e70f9d0203172afd17022f8bd058a2ddb8cc8e66de14524a561881d8070ca301d93aede144305c909c9a0fb9d389628bc69ee1dfeeff
|
7
|
+
data.tar.gz: da330328bb724784d21f0d1e59322f4eec091fbe57c48fc55ab03cee9238470867c8b321a2b833894a96cf69c80b830f528bfa800188b44b7744aee66516ca21
|
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
Copyright (c) 2025 Kazto TAKAHASHI (@kazto)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
5
|
+
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
7
|
+
|
8
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# xlg - Excel Grep Tool
|
2
|
+
|
3
|
+
`xlg` is a command-line tool that provides functionality to search keywords in Excel files in various formats. It works like `grep` but for Excel files, outputting results in a grep-like format showing file, sheet, cell reference, and matched content.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Search text in Excel files (.xlsx, .xls, .xlsm)
|
8
|
+
- Support for single file, multiple files, and directory-based searches
|
9
|
+
- Case-insensitive keyword matching
|
10
|
+
- Grep-like output format: `filename:sheet:cell_ref:matched_text`
|
11
|
+
- Automatic Excel file discovery in directories
|
12
|
+
- Comprehensive error handling and validation
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Build and install the gem:
|
17
|
+
|
18
|
+
```bash
|
19
|
+
gem build gemspec
|
20
|
+
gem install xlg-0.4.2.gem
|
21
|
+
```
|
22
|
+
|
23
|
+
Or install directly from the built gem files:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
gem install xlg-0.4.2.gem
|
27
|
+
```
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
### Basic Usage
|
32
|
+
|
33
|
+
```bash
|
34
|
+
# Search in a single Excel file
|
35
|
+
xlg 'keyword' sample.xlsx
|
36
|
+
|
37
|
+
# Search in multiple Excel files
|
38
|
+
xlg 'keyword' file1.xlsx file2.xlsx
|
39
|
+
|
40
|
+
# Search all Excel files in a directory
|
41
|
+
xlg 'keyword' /path/to/directory/
|
42
|
+
```
|
43
|
+
|
44
|
+
### Command Line Options
|
45
|
+
|
46
|
+
```
|
47
|
+
xlg KEYWORD FILE.xlsx # Single file search
|
48
|
+
xlg KEYWORD FILE1.xlsx FILE2.xlsx # Multiple file search
|
49
|
+
xlg KEYWORD /path/to/directory/ # Directory search
|
50
|
+
|
51
|
+
Options:
|
52
|
+
-h, --help Show help message
|
53
|
+
```
|
54
|
+
|
55
|
+
### Examples
|
56
|
+
|
57
|
+
```bash
|
58
|
+
# Search for "test" in sample.xlsx
|
59
|
+
xlg 'test' sample.xlsx
|
60
|
+
|
61
|
+
# Search for "データ" in multiple files
|
62
|
+
xlg 'データ' file1.xlsx file2.xlsx
|
63
|
+
|
64
|
+
# Search for "keyword" in all Excel files in documents folder
|
65
|
+
xlg 'キーワード' /home/user/documents/
|
66
|
+
```
|
67
|
+
|
68
|
+
## Output Format
|
69
|
+
|
70
|
+
The output follows a grep-like format:
|
71
|
+
|
72
|
+
```
|
73
|
+
filename.xlsx:SheetName:A1:matched content
|
74
|
+
filename.xlsx:SheetName:B5:another match
|
75
|
+
```
|
76
|
+
|
77
|
+
Where:
|
78
|
+
- `filename.xlsx`: The Excel file name
|
79
|
+
- `SheetName`: The worksheet name
|
80
|
+
- `A1`: Cell reference (Excel format)
|
81
|
+
- `matched content`: The actual cell content that contains the keyword
|
82
|
+
|
83
|
+
## Supported File Formats
|
84
|
+
|
85
|
+
- `.xlsx` (Excel 2007 and later)
|
86
|
+
- `.xls` (Excel 97-2003)
|
87
|
+
- `.xlsm` (Excel with macros)
|
88
|
+
|
89
|
+
## Requirements
|
90
|
+
|
91
|
+
- Ruby >= 3.0
|
92
|
+
- rubyXL gem (~> 3.4) - automatically installed as dependency
|
93
|
+
|
94
|
+
## Architecture
|
95
|
+
|
96
|
+
The tool consists of four main components:
|
97
|
+
|
98
|
+
- `ExcelGrep` (lib/excel_grep.rb): Core search functionality for single files
|
99
|
+
- `MultiFileSearcher` (lib/multi_file_searcher.rb): Handles multiple files and directories
|
100
|
+
- `CellMatcher` (lib/cell_matcher.rb): Performs case-insensitive text matching
|
101
|
+
- `OutputFormatter` (lib/output_formatter.rb): Formats output in grep-like style
|
102
|
+
|
103
|
+
## Development
|
104
|
+
|
105
|
+
### Running Tests
|
106
|
+
|
107
|
+
```bash
|
108
|
+
ruby test/test_*.rb
|
109
|
+
```
|
110
|
+
|
111
|
+
### Project Structure
|
112
|
+
|
113
|
+
```
|
114
|
+
├── lib/
|
115
|
+
│ ├── excel_grep.rb # Main Excel search engine
|
116
|
+
│ ├── multi_file_searcher.rb # Multi-file search coordination
|
117
|
+
│ ├── cell_matcher.rb # Text matching logic
|
118
|
+
│ └── output_formatter.rb # Output formatting
|
119
|
+
├── bin/
|
120
|
+
│ └── xlg # Command-line executable
|
121
|
+
├── test/ # Unit tests
|
122
|
+
├── docs/ # Documentation
|
123
|
+
└── gemspec # Gem specification
|
124
|
+
```
|
125
|
+
|
126
|
+
## License
|
127
|
+
|
128
|
+
MIT License - see LICENSE file for details.
|
129
|
+
|
130
|
+
## Author
|
131
|
+
|
132
|
+
Kazto TAKAHASHI (kazto@kazto.dev)
|
133
|
+
|
134
|
+
## Repository
|
135
|
+
|
136
|
+
https://github.com/kazto/xlg
|
data/bin/xlg
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'excel_grep'
|
4
|
+
require 'multi_file_searcher'
|
5
|
+
|
6
|
+
def show_help
|
7
|
+
puts "使用方法:"
|
8
|
+
puts " xlg KEYWORD FILE.xlsx # 単一ファイル"
|
9
|
+
puts " xlg KEYWORD FILE1.xlsx FILE2.xlsx # 複数ファイル"
|
10
|
+
puts " xlg KEYWORD /path/to/directory/ # ディレクトリ内全検索"
|
11
|
+
puts ""
|
12
|
+
puts "Excel ファイル内の文字列を検索し、grep形式で出力します。"
|
13
|
+
puts ""
|
14
|
+
puts "引数:"
|
15
|
+
puts " KEYWORD 検索するキーワード"
|
16
|
+
puts " FILE.xlsx 検索対象のExcelファイル(複数指定可能)"
|
17
|
+
puts " /path/to/dir/ 検索対象のディレクトリ"
|
18
|
+
puts ""
|
19
|
+
puts "対応ファイル形式:"
|
20
|
+
puts " .xlsx (Excel 2007以降)"
|
21
|
+
puts " .xls (Excel 97-2003)"
|
22
|
+
puts " .xlsm (マクロ有効Excel)"
|
23
|
+
puts ""
|
24
|
+
puts "例:"
|
25
|
+
puts " xlg 'test' sample.xlsx"
|
26
|
+
puts " xlg 'データ' file1.xlsx file2.xlsx"
|
27
|
+
puts " xlg 'キーワード' /home/user/documents/"
|
28
|
+
puts ""
|
29
|
+
puts "オプション:"
|
30
|
+
puts " -h, --help このヘルプを表示"
|
31
|
+
end
|
32
|
+
|
33
|
+
def main
|
34
|
+
if ARGV.include?('-h') || ARGV.include?('--help') || ARGV.length == 0
|
35
|
+
show_help
|
36
|
+
exit 0
|
37
|
+
end
|
38
|
+
|
39
|
+
if ARGV.length < 2
|
40
|
+
$stderr.puts "エラー: 引数の数が正しくありません"
|
41
|
+
$stderr.puts "使用方法: xlg KEYWORD FILE.xlsx [FILE2.xlsx ...]"
|
42
|
+
$stderr.puts "詳細は 'xlg --help' を参照してください"
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
|
46
|
+
keyword = ARGV[0]
|
47
|
+
paths = ARGV[1..-1]
|
48
|
+
|
49
|
+
begin
|
50
|
+
if paths.length == 1
|
51
|
+
# 単一ファイル/ディレクトリの場合
|
52
|
+
path = paths[0]
|
53
|
+
if File.directory?(path)
|
54
|
+
# ディレクトリの場合はMultiFileSearcherを使用
|
55
|
+
searcher = MultiFileSearcher.new(keyword, [path])
|
56
|
+
success = searcher.search
|
57
|
+
else
|
58
|
+
# 単一ファイルの場合はExcelGrepを使用
|
59
|
+
grep = ExcelGrep.new(keyword, path)
|
60
|
+
success = grep.search
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# 複数パスの場合はMultiFileSearcherを使用
|
64
|
+
searcher = MultiFileSearcher.new(keyword, paths)
|
65
|
+
success = searcher.search
|
66
|
+
end
|
67
|
+
|
68
|
+
exit(success ? 0 : 1)
|
69
|
+
rescue ArgumentError => e
|
70
|
+
$stderr.puts "エラー: #{e.message}"
|
71
|
+
exit 1
|
72
|
+
rescue => e
|
73
|
+
$stderr.puts "予期しないエラーが発生しました: #{e.message}"
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
main
|
data/lib/cell_matcher.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class CellMatcher
|
2
|
+
def match?(cell_value, keyword)
|
3
|
+
return false if cell_value.nil? || keyword.nil? || keyword.empty?
|
4
|
+
|
5
|
+
cell_str = cell_value.to_s
|
6
|
+
return false if cell_str.empty?
|
7
|
+
|
8
|
+
cell_str.downcase.include?(keyword.downcase)
|
9
|
+
end
|
10
|
+
|
11
|
+
def extract_match(cell_value, keyword)
|
12
|
+
return nil unless match?(cell_value, keyword)
|
13
|
+
|
14
|
+
cell_str = cell_value.to_s
|
15
|
+
keyword_lower = keyword.downcase
|
16
|
+
|
17
|
+
start_index = cell_str.downcase.index(keyword_lower)
|
18
|
+
return nil if start_index.nil?
|
19
|
+
|
20
|
+
cell_str[start_index, keyword.length]
|
21
|
+
end
|
22
|
+
end
|
data/lib/excel_grep.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubyXL'
|
2
|
+
require 'cell_matcher'
|
3
|
+
require 'output_formatter'
|
4
|
+
|
5
|
+
class ExcelGrep
|
6
|
+
attr_reader :keyword, :file_path
|
7
|
+
|
8
|
+
def initialize(keyword, file_path)
|
9
|
+
raise ArgumentError, "キーワードが空です" if keyword.nil? || keyword.empty?
|
10
|
+
raise ArgumentError, "ファイルパスが空です" if file_path.nil? || file_path.empty?
|
11
|
+
|
12
|
+
@keyword = keyword
|
13
|
+
@file_path = file_path
|
14
|
+
@matcher = CellMatcher.new
|
15
|
+
@formatter = OutputFormatter.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_file(file_path)
|
19
|
+
return false if file_path.nil? || file_path.empty?
|
20
|
+
return false unless File.exist?(file_path)
|
21
|
+
return false unless file_path.match?(/\.(xlsx?|xlsm)$/i)
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def search
|
27
|
+
unless validate_file(@file_path)
|
28
|
+
$stderr.puts "エラー: ファイルが見つかりません、またはExcelファイルではありません: #{@file_path}"
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
workbook = RubyXL::Parser.parse(@file_path)
|
34
|
+
file_name = File.basename(@file_path)
|
35
|
+
|
36
|
+
workbook.worksheets.each do |worksheet|
|
37
|
+
next if worksheet.nil?
|
38
|
+
|
39
|
+
sheet_name = worksheet.sheet_name || "Sheet#{worksheet.index + 1}"
|
40
|
+
|
41
|
+
worksheet.each_with_index do |row, row_index|
|
42
|
+
next if row.nil?
|
43
|
+
|
44
|
+
row.cells.each_with_index do |cell, col_index|
|
45
|
+
next if cell.nil? || cell.value.nil?
|
46
|
+
|
47
|
+
cell_value = cell.value.to_s
|
48
|
+
if @matcher.match?(cell_value, @keyword)
|
49
|
+
cell_ref = RubyXL::Reference.ind2ref(row_index, col_index)
|
50
|
+
puts @formatter.format(file_name, sheet_name, cell_ref, cell_value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
true
|
57
|
+
rescue => e
|
58
|
+
$stderr.puts "エラー: Excelファイルの読み込みに失敗しました: #{e.message}"
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'excel_grep'
|
2
|
+
|
3
|
+
class MultiFileSearcher
|
4
|
+
attr_reader :keyword, :paths
|
5
|
+
|
6
|
+
def initialize(keyword, paths)
|
7
|
+
raise ArgumentError, "キーワードが空です" if keyword.nil? || keyword.empty?
|
8
|
+
raise ArgumentError, "パスが空です" if paths.nil? || paths.empty?
|
9
|
+
|
10
|
+
@keyword = keyword
|
11
|
+
@paths = paths
|
12
|
+
end
|
13
|
+
|
14
|
+
def search
|
15
|
+
expanded_files = expand_paths(@paths)
|
16
|
+
success_count = 0
|
17
|
+
|
18
|
+
expanded_files.each do |file_path|
|
19
|
+
begin
|
20
|
+
grep = ExcelGrep.new(@keyword, file_path)
|
21
|
+
if grep.search
|
22
|
+
success_count += 1
|
23
|
+
end
|
24
|
+
rescue => e
|
25
|
+
$stderr.puts "エラー: #{file_path} - #{e.message}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
success_count > 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def expand_paths(paths)
|
33
|
+
expanded = []
|
34
|
+
|
35
|
+
paths.each do |path|
|
36
|
+
if File.directory?(path)
|
37
|
+
expanded.concat(find_excel_files(path))
|
38
|
+
else
|
39
|
+
expanded << path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
expanded.uniq
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_excel_files(directory)
|
47
|
+
return [] unless File.exist?(directory) && File.directory?(directory)
|
48
|
+
|
49
|
+
excel_files = []
|
50
|
+
|
51
|
+
begin
|
52
|
+
Dir.entries(directory).each do |entry|
|
53
|
+
next if entry.start_with?('.') # 隠しファイルとカレント/親ディレクトリを除外
|
54
|
+
|
55
|
+
file_path = File.join(directory, entry)
|
56
|
+
next if File.directory?(file_path) # サブディレクトリを除外
|
57
|
+
|
58
|
+
if entry.match?(/\.(xlsx?|xlsm)$/i)
|
59
|
+
excel_files << file_path
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rescue => e
|
63
|
+
$stderr.puts "ディレクトリ読み込みエラー: #{directory} - #{e.message}"
|
64
|
+
end
|
65
|
+
|
66
|
+
excel_files.sort
|
67
|
+
end
|
68
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xlg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kazto TAKAHASHI
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubyXL
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.4'
|
27
|
+
description: "`xlg` is a command-line tool that provides functionality to search keywords
|
28
|
+
in Excel files in various formats."
|
29
|
+
email:
|
30
|
+
- kazto@kazto.dev
|
31
|
+
executables:
|
32
|
+
- xlg
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- bin/xlg
|
39
|
+
- lib/cell_matcher.rb
|
40
|
+
- lib/excel_grep.rb
|
41
|
+
- lib/multi_file_searcher.rb
|
42
|
+
- lib/output_formatter.rb
|
43
|
+
homepage: https://github.com/kazto/xlg
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubygems_version: 3.4.19
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: A Ruby library for reading and writing Excel files.
|
66
|
+
test_files: []
|