Skip to content

Ruby 正则表达式

正则表达式(Regular Expression,简称regex或regexp)是处理文本的强大工具。在Ruby中,正则表达式被广泛应用于字符串验证、文本搜索、数据提取和格式化等场景。Ruby对正则表达式提供了原生支持,使其成为处理文本数据的理想选择。本章将详细介绍Ruby中正则表达式的语法、方法和实际应用。

🎯 正则表达式基础

什么是正则表达式

正则表达式是一种特殊的文本字符串,用于描述搜索模式。它由普通字符和特殊字符(元字符)组成,可以用来匹配、查找、替换文本中的特定模式。

ruby
# 基本正则表达式匹配
# 检查字符串是否包含数字
text = "我的电话号码是13812345678"
if text.match?(/\d+/)
  puts "文本包含数字"
end

# 查找匹配的内容
match = text.match(/\d+/)
if match
  puts "找到数字: #{match[0]}"  # 13812345678
end

# 使用字符串方法
puts "hello".match?(/h/)  # true
puts "hello".match?(/H/)  # false
puts "hello".match?(/H/i) # true (忽略大小写)

正则表达式字面量

ruby
# 使用斜杠定义正则表达式
regex1 = /hello/
regex2 = /\d+/          # 匹配一个或多个数字
regex3 = /[a-z]+/       # 匹配一个或多个小写字母
regex4 = /hello/i       # 忽略大小写

# 使用%r定义正则表达式(避免转义斜杠)
url_pattern = %r{https?://[\w\-\.]+\.[a-zA-Z]{2,}(/\S*)?}
email_pattern = %r{[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+}

# 使用Regexp.new创建
pattern = Regexp.new('\d+', Regexp::IGNORECASE)

# 正则表达式选项
# i - 忽略大小写
# m - 多行模式
# x - 扩展模式(忽略空白和注释)
regex_with_options = /hello world/imx

🔤 基本元字符

字符匹配

ruby
# 普通字符
/hello/.match("hello world")  # 匹配

# 点号 - 匹配任意字符(除换行符)
/a.c/.match("abc")    # 匹配
/a.c/.match("a c")    # 匹配
/a.c/.match("axc")    # 匹配
/a.c/.match("ac")     # 不匹配

# 转义字符
/\./.match("a.b")     # 匹配点号
/\*/.match("a*b")     # 匹配星号
/\?/.match("a?b")     # 匹配问号

# 字符类
/[abc]/.match("a")    # 匹配
/[abc]/.match("b")    # 匹配
/[abc]/.match("d")    # 不匹配

# 范围
/[a-z]/.match("m")    # 匹配小写字母
/[A-Z]/.match("M")    # 匹配大写字母
/[0-9]/.match("5")    # 匹配数字
/[a-zA-Z0-9]/.match("K")  # 匹配字母或数字

# 预定义字符类
/\d/.match("5")       # 匹配数字 [0-9]
/\D/.match("a")       # 匹配非数字 [^0-9]
/\w/.match("a")       # 匹配单词字符 [a-zA-Z0-9_]
/\W/.match("@")       # 匹配非单词字符 [^a-zA-Z0-9_]
/\s/.match(" ")       # 匹配空白字符 [ \t\r\n\f]
/\S/.match("a")       # 匹配非空白字符

量词

ruby
# 基本量词
/a*/.match("")        # 匹配零个或多个a
/a*/.match("a")       # 匹配
/a*/.match("aaa")     # 匹配

/a+/.match("a")       # 匹配一个或多个a
/a+/.match("aaa")     # 匹配
/a+/.match("")        # 不匹配

/a?/.match("")        # 匹配零个或一个a
/a?/.match("a")       # 匹配
/a?/.match("aa")      # 只匹配第一个a

# 精确量词
/a{3}/.match("aaa")   # 匹配恰好3个a
/a{2,4}/.match("aa")  # 匹配2到4个a
/a{2,}/.match("aaaa") # 匹配2个或更多a

# 贪婪与非贪婪匹配
/<.+>/.match("<b>bold</b>")     # 贪婪匹配: <b>bold</b>
/<.+?>/.match("<b>bold</b>")    # 非贪婪匹配: <b>

# 实际应用示例
text = "手机号码: 13812345678, 座机: 010-12345678"

# 提取手机号
phone_match = text.match(/1[3-9]\d{9}/)
puts phone_match[0] if phone_match  # 13812345678

# 提取座机号
landline_match = text.match(/0\d{2,3}-?\d{7,8}/)
puts landline_match[0] if landline_match  # 010-12345678

🏗️ 高级正则表达式

分组和捕获

ruby
# 基本分组
/(ab)+/.match("ababab")  # 匹配ab的重复

// 使用分组捕获
match = /(\d{4})-(\d{2})-(\d{2})/.match("2023-12-25")
if match
  puts "年: #{match[1]}"  # 2023
  puts "月: #{match[2]}"  # 12
  puts "日: #{match[3]}"  # 25
  puts "完整匹配: #{match[0]}"  # 2023-12-25
end

// 命名分组
match = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.match("2023-12-25")
if match
  puts "年: #{match[:year]}"    # 2023
  puts "月: #{match[:month]}"   # 12
  puts "日: #{match[:day]}"     # 25
end

// 非捕获分组
/(?:abc)+/.match("abcabc")  # 匹配但不捕获

// 分组引用
/(.)\1/.match("aa")  # 匹配重复字符
/(..)\1/.match("abab")  # 匹配重复的两个字符

// 实际应用:解析URL
url = "https://www.example.com:8080/path/to/page?param1=value1&param2=value2#section"
url_pattern = %r{(?<protocol>https?)://(?<host>[\w\-\.]+)(?::(?<port>\d+))?(?<path>/[^?#]*)?(?:\?(?<query>[^#]*))?(?:#(?<fragment>.*))?}

match = url_pattern.match(url)
if match
  puts "协议: #{match[:protocol]}"  # https
  puts "主机: #{match[:host]}"      # www.example.com
  puts "端口: #{match[:port]}"      # 8080
  puts "路径: #{match[:path]}"      # /path/to/page
  puts "查询: #{match[:query]}"     # param1=value1&param2=value2
  puts "片段: #{match[:fragment]}"  # section
end

锚点和边界

ruby
// 行首和行尾锚点
/^hello/.match("hello world")  // 匹配行首
/world$/.match("hello world")  // 匹配行尾

// 单词边界
/\bword\b/.match("word")       // 匹配完整单词
/\bword\b/.match("wording")    // 不匹配
/\bword/.match("wording")      // 匹配单词开头
/word\b/.match("reword")       // 匹配单词结尾

// 字符串边界
/\Ahello/.match("hello world") // 匹配字符串开头
/world\z/.match("hello world") // 匹配字符串结尾

// 实际应用:验证输入
def valid_username?(username)
  // 用户名只能包含字母、数字、下划线,长度3-16位
  username.match?(/\A[a-zA-Z0-9_]{3,16}\z/)
end

def valid_email?(email)
  // 简单的邮箱验证
  email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
end

puts valid_username?("user_123")  // true
puts valid_username?("us")        // false
puts valid_email?("user@example.com")  // true
puts valid_email?("invalid.email")     // false

选择和条件

ruby
// 或操作符
/(cat|dog)/.match("I have a cat")  // 匹配cat
/(cat|dog)/.match("I have a dog")  // 匹配dog

// 复杂选择
/(https?|ftp):\/\//.match("https://example.com")  // 匹配协议
/(https?|ftp):\/\//.match("ftp://example.com")    // 匹配协议

// 条件匹配
// 如果前面匹配了某个模式,则后面必须匹配另一个模式
/(?<=\d{3})\d{4}/.match("13812345678")  // 匹配1234(前面有3位数字)

// 负向先行断言
/(?<!\d{3})\d{4}/.match("12345678")  // 匹配1234(前面不是3位数字)

// 实际应用:提取多种格式的日期
text = "今天是2023-12-25,明天是2023/12/26,后天是Dec 27, 2023"

date_patterns = [
  /(\d{4})-(\d{2})-(\d{2})/,     // 2023-12-25
  /(\d{4})\/(\d{2})\/(\d{2})/,   // 2023/12/26
  /(\w{3})\s+(\d{1,2}),\s+(\d{4})/  // Dec 27, 2023
]

text.scan(Regexp.union(date_patterns)) do |match|
  puts "找到日期: #{match.compact}"
end

🔧 正则表达式方法

字符串中的正则表达式方法

ruby
text = "联系方式:电话13812345678,邮箱user@example.com"

// match方法 - 返回匹配对象
match = text.match(/1[3-9]\d{9}/)
if match
  puts "电话: #{match[0]}"
end

// match?方法 - 返回布尔值
puts text.match?(/1[3-9]\d{9}/)  // true

// scan方法 - 查找所有匹配
text = "价格:100元,折扣:80元,运费:10元"
prices = text.scan(/\d+/)
puts prices.inspect  // ["100", "80", "10"]

// gsub方法 - 全局替换
masked_text = text.gsub(/1[3-9]\d{9}/, "****")
puts masked_text

// sub方法 - 替换第一个匹配
first_replaced = text.sub(/\d+/, "***")
puts first_replaced

// split方法 - 使用正则表达式分割
data = "apple,banana;orange:grape"
fruits = data.split(/[,;:]/)
puts fruits.inspect  // ["apple", "banana", "orange", "grape"]

// 实际应用:数据清洗
def clean_phone_numbers(text)
  // 提取并格式化电话号码
  text.gsub(/(\d{3})(\d{4})(\d{4})/) do |match|
    "#{$1}-#{$2}-#{$3}"
  end
end

text = "联系电话:13812345678,备用电话:13987654321"
puts clean_phone_numbers(text)
// 联系电话:138-1234-5678,备用电话:139-8765-4321

Regexp类方法

ruby
// 编译正则表达式
pattern = Regexp.new('\d+', Regexp::IGNORECASE)
puts pattern.match?("123abc")  // true

// 转义特殊字符
special_chars = "hello*world?.+"
escaped = Regexp.escape(special_chars)
puts escaped  // hello\*world\?\.\+

// 联合多个正则表达式
patterns = [/cat/, /dog/, /bird/]
union_pattern = Regexp.union(patterns)
puts "I have a cat".match?(union_pattern)  // true

// 获取正则表达式选项
regex = /hello/i
puts regex.options  // 1 (对应Regexp::IGNORECASE)

// 检查正则表达式是否相等
regex1 = /hello/
regex2 = /hello/
puts regex1 == regex2  // true

🎯 实用正则表达式示例

数据验证

ruby
class DataValidator
  // 邮箱验证
  EMAIL_PATTERN = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  
  // 手机号验证
  PHONE_PATTERN = /\A1[3-9]\d{9}\z/
  
  // 身份证验证
  ID_CARD_PATTERN = /\A\d{17}[\dXx]\z/
  
  // 邮编验证
  POSTAL_CODE_PATTERN = /\A\d{6}\z/
  
  // URL验证
  URL_PATTERN = /\Ahttps?:\/\/[\w\-\.]+\.[a-zA-Z]{2,}(/\S*)?\z/
  
  // 密码强度验证
  PASSWORD_PATTERN = /\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{8,}\z/
  
  def self.valid_email?(email)
    email.match?(EMAIL_PATTERN)
  end
  
  def self.valid_phone?(phone)
    phone.match?(PHONE_PATTERN)
  end
  
  def self.valid_id_card?(id_card)
    id_card.match?(ID_CARD_PATTERN)
  end
  
  def self.valid_postal_code?(code)
    code.match?(POSTAL_CODE_PATTERN)
  end
  
  def self.valid_url?(url)
    url.match?(URL_PATTERN)
  end
  
  def self.strong_password?(password)
    password.match?(PASSWORD_PATTERN)
  end
end

// 使用数据验证器
puts DataValidator.valid_email?("user@example.com")      // true
puts DataValidator.valid_phone?("13812345678")           // true
puts DataValidator.valid_id_card?("110101199001011234")  // true
puts DataValidator.strong_password?("Password123!")      // true

文本处理和提取

ruby
class TextProcessor
  // 提取所有邮箱地址
  def self.extract_emails(text)
    email_pattern = /[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+/i
    text.scan(email_pattern)
  end
  
  // 提取所有电话号码
  def self.extract_phones(text)
    phone_pattern = /1[3-9]\d{9}|\d{3,4}-?\d{7,8}/
    text.scan(phone_pattern)
  end
  
  // 提取所有URL
  def self.extract_urls(text)
    url_pattern = %r{https?://[\w\-\.]+\.[a-zA-Z]{2,}(/\S*)?}
    text.scan(url_pattern)
  end
  
  // 提取HTML标签内容
  def self.extract_html_content(html)
    html.gsub(/<[^>]*>/, "")
  end
  
  // 清理多余空白
  def self.clean_whitespace(text)
    text.gsub(/\s+/, " ").strip
  end
  
  // 格式化电话号码
  def self.format_phone(phone)
    phone.gsub(/(\d{3})(\d{4})(\d{4})/, '\1-\2-\3')
  end
  
  // 提取引号内的内容
  def self.extract_quoted_text(text)
    text.scan(/["']([^"']*)["']/).flatten
  end
end

// 使用文本处理器
text = <<~TEXT
  联系我们:
  邮箱:contact@example.com, support@company.org
  电话:13812345678, 010-12345678
  网站:https://www.example.com
  "这是一段引用文本"
  '这是另一段引用文本'
TEXT

puts "邮箱地址:"
TextProcessor.extract_emails(text).each { |email| puts "  #{email}" }

puts "电话号码:"
TextProcessor.extract_phones(text).each { |phone| puts "  #{phone}" }

puts "URL:"
TextProcessor.extract_urls(text).each { |url| puts "  #{url}" }

puts "格式化电话: #{TextProcessor.format_phone('13812345678')}"
puts "清理空白: '#{TextProcessor.clean_whitespace("  多个   空白   字符  ")}'"

日志分析

ruby
class LogAnalyzer
  // Apache访问日志模式
  APACHE_LOG_PATTERN = /
    ^(\S+)\s+                // IP地址
    (\S+)\s+                 // 标识符
    (\S+)\s+                 // 用户ID
    \[([^\]]+)\]\s+          // 时间戳
    "(\S+)\s+(\S+)\s+(\S+)"\s+  // 请求行
    (\d{3})\s+               // 状态码
    (\d+|-)\s+               // 响应大小
    "(.*?)"\s+               // 引用页
    "(.*?)"                  // 用户代理
  /x
  
  // 错误日志模式
  ERROR_LOG_PATTERN = /
    ^\[([^\]]+)\]\s+         // 时间戳
    \[([^\]]+)\]\s+          // 日志级别
    \[([^\]]+)\]\s+          // 进程ID
    (.*)                     // 错误消息
  /x
  
  def self.parse_apache_log(line)
    match = line.match(APACHE_LOG_PATTERN)
    return nil unless match
    
    {
      ip: match[1],
      timestamp: match[4],
      method: match[5],
      path: match[6],
      protocol: match[7],
      status: match[8].to_i,
      size: match[9] == '-' ? 0 : match[9].to_i,
      referrer: match[10],
      user_agent: match[11]
    }
  end
  
  def self.parse_error_log(line)
    match = line.match(ERROR_LOG_PATTERN)
    return nil unless match
    
    {
      timestamp: match[1],
      level: match[2],
      pid: match[3],
      message: match[4]
    }
  end
  
  // 统计访问次数
  def self.count_visits(log_lines)
    visits = Hash.new(0)
    log_lines.each do |line|
      record = parse_apache_log(line)
      next unless record
      
      visits[record[:ip]] += 1
    end
    visits
  end
  
  // 统计状态码
  def self.count_status_codes(log_lines)
    status_codes = Hash.new(0)
    log_lines.each do |line|
      record = parse_apache_log(line)
      next unless record
      
      status_codes[record[:status]] += 1
    end
    status_codes
  end
end

// 使用日志分析器
apache_log_line = '127.0.0.1 - - [25/Dec/2023:14:30:45 +0800] "GET /index.html HTTP/1.1" 200 1234 "http://example.com" "Mozilla/5.0"'
error_log_line = '[2023-12-25 14:30:45] [ERROR] [12345] Database connection failed'

apache_record = LogAnalyzer.parse_apache_log(apache_log_line)
error_record = LogAnalyzer.parse_error_log(error_log_line)

puts "Apache日志记录:"
puts apache_record.inspect if apache_record

puts "错误日志记录:"
puts error_record.inspect if error_record

📊 性能优化

正则表达式性能考虑

ruby
// 避免回溯灾难
// 不好的模式
bad_pattern = /a+b+a+b+a+b+a+b+a+b+a+b+a+b+a+b+a+b+/

// 好的模式 - 使用原子组或占有量词
good_pattern = /a++b+a++b+a++b+a++b+a++b+a++b+a++b+a++b+/

// 预编译常用的正则表达式
class RegexCache
  @@cache = {}
  
  def self.get(pattern)
    @@cache[pattern] ||= Regexp.new(pattern)
  end
end

// 使用缓存的正则表达式
def find_emails_cached(text)
  email_pattern = RegexCache.get('[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+')
  text.scan(email_pattern)
end

// 避免不必要的捕获
// 不需要捕获时使用非捕获分组
non_capturing = /(?:abc)+/
capturing = /(abc)+/

// 使用锚点提高匹配效率
// 好的做法
/^start.*end$/.match("start something end")

// 避免在大文本中使用贪婪匹配
// 使用非贪婪匹配或更精确的模式
text = "a" * 1000 + "b"
//
slow_pattern = /a+b/
//
fast_pattern = /a++b/

// 批量处理优化
def process_large_text(text)
  // 分块处理大文本
  chunk_size = 10000
  results = []
  
  0.step(text.length, chunk_size) do |i|
    chunk = text[i, chunk_size]
    results.concat(chunk.scan(/\b\w{4,}\b/))
  end
  
  results
end

正则表达式调试

ruby
// 调试正则表达式
def debug_regex(pattern, text)
  regex = Regexp.new(pattern)
  match = text.match(regex)
  
  if match
    puts "匹配成功!"
    puts "完整匹配: #{match[0]}"
    puts "匹配位置: #{match.begin(0)}-#{match.end(0)}"
    
    match.captures.each_with_index do |capture, index|
      puts "分组#{index + 1}: #{capture} (位置: #{match.begin(index + 1)}-#{match.end(index + 1)})"
    end
  else
    puts "匹配失败"
  end
end

// 使用调试函数
debug_regex(/(\d{4})-(\d{2})-(\d{2})/, "今天是2023-12-25")

// 性能测试
def benchmark_regex(pattern, text, iterations = 1000)
  regex = Regexp.new(pattern)
  start_time = Time.now
  
  iterations.times do
    text.match?(regex)
  end
  
  end_time = Time.now
  puts "执行#{iterations}次耗时: #{end_time - start_time}秒"
end

// benchmark_regex('\d+', 'abc123def456ghi789')

🛡️ 正则表达式最佳实践

1. 编写可维护的正则表达式

ruby
// 使用扩展模式提高可读性
complex_pattern = /
  ^                    // 行首
  (?<protocol>https?)  // 协议组
  :\/\/                // 分隔符
  (?<host>             // 主机组
    [\w\-\.]+          // 域名字符
    \.                 // 点号
    [a-zA-Z]{2,}       // 顶级域名
  )
  (?::(?<port>\d+))?   // 可选端口组
  (?<path>\/[^?#]*)?   // 可选路径组
  (?:\?(?<query>[^#]*))?  // 可选查询组
  (?:\#(?<fragment>.*))?  // 可选片段组
  $                    // 行尾
/x

// 分解复杂正则表达式
class EmailValidator
  LOCAL_PART = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+'
  DOMAIN_PART = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?'
  DOMAIN = "#{DOMAIN_PART}(?:\\.#{DOMAIN_PART})*"
  TLD = '[a-zA-Z]{2,}'
  
  EMAIL_PATTERN = /\A#{LOCAL_PART}@#{DOMAIN}\.#{TLD}\z/
  
  def self.valid?(email)
    email.match?(EMAIL_PATTERN)
  end
end

// 使用命名常量
PHONE_PATTERN = /\A1[3-9]\d{9}\z/
ID_CARD_PATTERN = /\A\d{17}[\dXx]\z/

def valid_phone?(phone)
  phone.match?(PHONE_PATTERN)
end

def valid_id_card?(id_card)
  id_card.match?(ID_CARD_PATTERN)
end

2. 安全考虑

ruby
// 防止正则表达式拒绝服务攻击(ReDoS)
class SafeRegex
  // 设置匹配超时(Ruby 2.6+
  def self.safe_match?(pattern, string, timeout: 1)
    regex = Regexp.new(pattern)
    
    // 在新线程中执行匹配
    thread = Thread.new { string.match?(regex) }
    result = thread.join(timeout)
    
    if result
      thread.value
    else
      thread.kill
      raise "正则表达式匹配超时"
    end
  end
  
  // 验证用户输入的正则表达式
  def self.validate_user_regex(pattern)
    begin
      Regexp.new(pattern)
      true
    rescue RegexpError
      false
    end
  end
  
  // 清理用户输入
  def self.sanitize_input(input)
    // 移除潜在危险的字符
    input.gsub(/[<>'"&]/, '')
  end
end

// 使用安全正则表达式
begin
  result = SafeRegex.safe_match?('\d+', '12345')
  puts "匹配结果: #{result}"
rescue => e
  puts "错误: #{e.message}"
end

3. 测试正则表达式

ruby
// 正则表达式测试框架
class RegexTester
  def initialize(pattern)
    @pattern = pattern
    @regex = Regexp.new(pattern)
  end
  
  def test_positive(*strings)
    strings.each do |string|
      unless string.match?(@regex)
        puts "失败: '#{string}' 应该匹配模式 '#{@pattern}'"
        return false
      end
    end
    true
  end
  
  def test_negative(*strings)
    strings.each do |string|
      if string.match?(@regex)
        puts "失败: '#{string}' 不应该匹配模式 '#{@pattern}'"
        return false
      end
    end
    true
  end
  
  def test_capture(string, expected_captures)
    match = string.match(@regex)
    if match
      actual_captures = match.captures
      if actual_captures == expected_captures
        true
      else
        puts "捕获失败: 期望 #{expected_captures}, 实际 #{actual_captures}"
        false
      end
    else
      puts "匹配失败: '#{string}' 没有匹配"
      false
    end
  end
end

// 使用测试框架
email_tester = RegexTester.new('[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+')

// 测试正例
email_tester.test_positive(
  'user@example.com',
  'test.email@domain.org',
  'user123@test-domain.co.uk'
)

// 测试反例
email_tester.test_negative(
  'invalid.email',
  '@example.com',
  'user@',
  'user@.com'
)

// 测试捕获组
date_tester = RegexTester.new('(\d{4})-(\d{2})-(\d{2})')
date_tester.test_capture('2023-12-25', ['2023', '12', '25'])

4. 实际应用场景

ruby
// 配置文件解析器
class ConfigParser
  SECTION_PATTERN = /^\[(.+)\]$/
  KEY_VALUE_PATTERN = /^([^=]+)=(.*)$/
  COMMENT_PATTERN = /^\s*[#;]/
  
  def self.parse(config_text)
    config = {}
    current_section = 'default'
    
    config_text.each_line do |line|
      line = line.strip
      next if line.empty? || line.match?(COMMENT_PATTERN)
      
      if section_match = line.match(SECTION_PATTERN)
        current_section = section_match[1]
        config[current_section] = {}
      elsif kv_match = line.match(KEY_VALUE_PATTERN)
        key = kv_match[1].strip
        value = kv_match[2].strip
        config[current_section] ||= {}
        config[current_section][key] = value
      end
    end
    
    config
  end
end

// 使用配置解析器
config_text = <<~CONFIG
  # 应用配置
  [database]
  host = localhost
  port = 5432
  username = admin
  
  [logging]
  level = info
  file = app.log
CONFIG

config = ConfigParser.parse(config_text)
puts config.inspect

// CSV解析器
class CSVParser
  CSV_LINE_PATTERN = /(?<=^|,)(?:"([^"]*)"|([^",]*))(?=,|$)/
  
  def self.parse_line(line)
    matches = line.scan(CSV_LINE_PATTERN)
    matches.map { |match| match[0] || match[1] || '' }
  end
  
  def self.parse(csv_text)
    csv_text.each_line.map { |line| parse_line(line.chomp) }
  end
end

// 使用CSV解析器
csv_text = <<~CSV
  "姓名","年龄","城市"
  "张三","25","北京"
  "李四","30","上海"
CSV

data = CSVParser.parse(csv_text)
data.each { |row| puts row.inspect }

📚 下一步学习

掌握了Ruby正则表达式后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。