【问题标题】:reading integers from a string从字符串中读取整数
【发布时间】:2016-08-09 02:56:36
【问题描述】:

我想从文件中读取一行,从该行初始化一个数组,然后显示整数。 为什么不读取行中的五个整数?我要输出1 2 3 4 5,我有1 1 1 1 1

open Array;;
open Scanf;;

let print_ints file_name = 
  let file = open_in file_name in
  let s = input_line(file) in
  let n = ref 5 in
  let arr = Array.init !n (fun i -> if i < !n then sscanf s "%d" (fun a -> a) else 0) in
  let i = ref 0 in 
  while !i < !n do
    print_int (Array.get arr !i);
    print_string " ";
    i := !i + 1;
  done;;

print_ints "string_ints.txt";;

我的文件是:1 2 3 4 5

【问题讨论】:

  • 为什么不读取行中的五个整数?我想得到输出 1 2 3 4 5,我有 11111
  • 就是这部分sscanf s "%d" (fun a -&gt; a):你总是从一开始就扫描同一个字符串ssscanf 不会改变你的字符串。
  • 我能做些什么来从字符串中获取所有整数?有 int_of_string 但会尝试将整个字符串转换为数字。还有 get 但这只会给我 char 而不是整数。

标签: string ocaml


【解决方案1】:

您可能想尝试以下方法。将您的字符串拆分为表示数字的子字符串列表。 This answer 描述了一种这样做的方法。然后在 print_ints 函数中使用生成的函数。

let ints_of_string s = 
  List.map int_of_string (Str.split (Str.regexp " +") s)

let print_ints file_name = 
  let file = open_in file_name in
  let s = input_line file in
  let ints = ints_of_string s in
  List.iter (fun i -> print_int i; print_char ' ') ints;
  close_in file

let _ = print_ints "string_ints.txt"

编译时,将str.cmastr.cmxa 作为参数传递(有关编译的详细信息,请参阅this answer):

$ ocamlc str.cma print_ints.ml

另一种选择是使用Scanf.bscanf 函数——this question,包含一个示例(谨慎使用)。

Scanf.sscanf 函数可能不是特别适合此任务。 摘自OCaml manual

scanf 工具不适用于繁重的词法分析和解析。如果它的表达能力不足以满足您的需求,则存在几种替代方法:正则表达式(模块 Str)、流解析器、ocamllex 生成的词法分析器、ocamlyacc 生成的解析器

虽然有一种方法可以使用 Scanf.sscanf 解析一串整数(我不推荐):

let rec int_list_of_string s =
  try
    Scanf.sscanf s 
                 "%d %[0-9-+ ]" 
                 (fun n rest_str -> n :: int_list_of_string rest_str)
  with
    | End_of_file | Scanf.Scan_failure _ -> []

这里的技巧是将输入字符串 s 表示为将被解析为整数 (%d) 的一部分,字符串的其余部分使用范围格式:%[0-9-+ ]",这将匹配字符串的其余部分,仅包含十进制数字 0-9-+ 符号以及空格

【讨论】:

  • 这样就解决了问题。 Ocaml 对于地图之类的东西非常强大,但对于扫描来说,似乎不得不使用外部东西。使用 sscanf 我可以做到吗?似乎我总是需要知道格式有多少个整数。
  • Str 是一个标准模块(不是外部的),只是编译有点复杂。是的,你必须修复你的格式字符串(我已经更新了答案以反映这一点)。
  • 您可能会喜欢这个tutorial on streams。您可以在let int_stream_of_string s = Stream.of_list (List.map int_of_string (Str.split (Str.regexp " +") s)) 使用流来逐段处理您的字符串。
  • 您的拆分不会处理负数。
  • @vanmarcke 我添加了一个带有sscanf 的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多