You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用非递归Guard校验字符串仅含0和1?(Elixir)

问题描述

需要实现一个校验逻辑,确保输入字符串的每个字符均为"0"或"1"。尝试通过递归defguard实现时出现编译错误:

(CompileError) cannot find or invoke local is_bit_string/1 inside guards. Only macros can be invoked in a guards and they must be defined before their invocation. Called as: is_bit_string(binary_part(str, 1, byte_size(str) - 1))

若在每个函数体内编写校验逻辑会造成代码冗余,求无需重复编写的替代方案。

此前尝试的代码:

defguard is_bit_string(str)
         when is_binary(str) and
                byte_size(str) == 1 and
                binary_part(str, 0, 1) in ["0", "1"]

defguard is_bit_string(str)
         # byte_size(str) == 1 and
         when is_binary(str) and
                binary_part(str, 0, 1) in ["0", "1"] and
                is_bit_string(binary_part(str, 1, byte_size(str) - 1))
解决方案

方案1:正则表达式配合defguard

直接用正则匹配所有字符为0或1的字符串,简洁且适配guard场景:

defguard is_bit_string(str)
         when is_binary(str) and
                Regex.match?(~r/^[01]*$/, str)
  • 正则^[01]*$表示从字符串开头到结尾,所有字符只能是0或1,默认允许空字符串;若要禁止空字符串,将*替换为+即可。
  • Regex.match?/2是Elixir允许在guard中调用的纯函数,符合guard的约束要求。

方案2:字节级检查的函数封装(非guard场景)

如果需要更底层的字节检查,可封装一个纯函数,在需要校验的地方统一调用:

def is_bit_string?(str) when is_binary(str) do
  Enum.all?(String.to_charlist(str), &(&1 in [?0, ?1]))
end
  • 将字符串转为字符列表后,检查每个字符的ASCII值是否为?0(48)或?1(49)。
  • 该函数无法直接用于guard,但能避免在多个函数体内重复编写校验逻辑。

方案3:模式匹配+多子句函数(固定长度场景)

若目标字符串长度固定或范围有限,可通过模式匹配覆盖所有合法情况:

defguard is_bit_string(str)
         when is_binary(str) and
                (str == "" or
                 str == "0" or
                 str == "1" or
                 str == "00" or
                 str == "01" or
                 str == "10" or
                 str == "11")

此方式仅适用于长度有限的场景,不支持任意长度的字符串校验。

补充说明

递归defguard不可行的原因:Elixir的defguard本质是宏,但guard clauses不支持递归调用自定义guard——宏展开时会出现未定义引用(第二个defguard覆盖了第一个,递归调用时宏尚未完全定义),同时guard要求所有表达式必须是编译时可确定的纯逻辑,递归调用不符合该约束。

内容的提问来源于stack exchange,提问作者lorem1213

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:03:16