Elixir 从零 · 第 27 课(展开目录)
01 · 先让代码说话02 · 先认六种值03 · 把值装起来04 · 从旧 list 生成新 list05 · 让形状对上06 · 用 case 做选择07 · 把文字安全变成整数08 · 拆开 &1 和管道09 · 把代码放进项目10 · 真假不只靠 true11 · 走进嵌套数据12 · 一字不一定一字节13 · 让函数按形状接活14 · 把一列数收成一个值15 · 给不同问题选不同路16 · 给 map 一张名片17 · 让项目自己验答案18 · 让成功和失败长得一样19 · 读写文件先管好路20 · 只算眼前需要的21 · 同一句话,不同做法22 · 先约好模块会做什么23 · 把数据形状写在门口24 · 测试不只看一条好路25 · 把项目磨成一个命令26 · 定下小项目边界27 · 把真实文字洗干净28 · 只开三扇门29 · 把约定钉在代码旁30 · 打包,也留下脚印31 · 照任务书交卷
ELIXIR · 作品 · LESSON 2745 分钟

把真实文字洗干净

读 UTF-8 文件,统一换行,再把内容解析成可统计数据。

01 · 先看完整例子

把文件变成非空行

把代码放进 lib/trail_stats/parser.ex,再用临时文件测试。

Elixir
defmodule TrailStats.Parser do
  @spec read(Path.t()) :: {:ok, [String.t()]} | {:error, term()}
  def read(path) do
    with {:ok, text} <- File.read(path),
         true <- String.valid?(text) do
      # 同时接受 Unix 与 Windows 换行
      lines = String.split(text, ~r/\R/u, trim: true)
      {:ok, lines}
    else
      false -> {:error, :invalid_utf8}
      {:error, reason} -> {:error, reason}
    end
  end
end
先对照结果
  • 有效文件返回 {:ok, lines};不存在文件保留 {:error, :enoent} 等系统原因。
02 · 回头拆代码

从第一行往下读

  1. File.read/1 先建立文件边界。
  2. UTF-8 检查通过后才调用字符串函数。
  3. 正则 \R 接受常见换行,trim: true 去掉空行。
03 · 认清新符号

符号不是暗号

String.valid?/1

检查 binary 是否是有效 UTF-8 字符串。

String.split/3

按换行切开,并可去掉空项。

{:error, reason}

把文件或编码错误交给上层。

04 · 代码里的概念

把名字和意思对上

01

解析层

把外部原始数据变成项目内部约定的数据形状。

02

规范化

把多种等价输入整理成一种稳定形式,如统一换行。

05 · 再说清楚

这些写法为什么有用

真实文件可能有空行,也可能使用不同换行符。先把输入整理成稳定形状,后续统计才简单。

解析层负责从文件路径得到行 list。它不打印、不退出程序,也不计算最终统计。

保留 File 的错误原因,另把非法 UTF-8 转为项目自己的 :invalid_utf8。

06 · 自己改一次

合上答案,动手

为只有两行的临时文件写一个 Parser 测试。

练习起点
path = Path.join(System.tmp_dir!(), "trail_stats_test.txt")
File.write!(path, "长安\n春风\n")

assert TrailStats.Parser.read(path) == ____

目标结果: 期待 {:ok, ["长安", "春风"]}。

卡住了,再看提示

成功 tuple 的第二项是两行字符串 list。

运行过以后,再看一种答案
一种答案
path = Path.join(System.tmp_dir!(), "trail_stats_test.txt")
File.write!(path, "长安
春风
")

# Parser 只返回清洗后的行
assert TrailStats.Parser.read(path) == {:ok, ["长安", "春风"]}
想一想:Parser 为什么不在失败时直接 `IO.puts`?

打印属于命令边界。Parser 返回数据后,测试、网页或 CLI 都能选择自己的显示方式。

带走

记住三句

  1. 1

    外部输入先验证,再解析。

  2. 2

    解析层返回数据,不负责显示。

  3. 3

    错误原因应能继续交给上层判断。

本课结束代码也跑过一次,就把这一课收好。