Как мне прочитать в строках текстового файла, когда разрывы строк - "/ r" вместо "/ n"? - PullRequest
3 голосов
/ 26 апреля 2011

У меня есть массивный файл .txt со списком десятков тысяч прилагательных.В текстовых файлах каждое слово находится на отдельной строке.Я прочитал его в список (который я затем поместил в массив, используя Array.of_list) со следующей функцией:

let read_file filename = 
    let lines = ref [] in
    let chan = open_in filename in
      try
        while true; do
      lines := input_line chan :: !lines
        done; []
      with End_of_file ->
        close_in chan;
        List.rev !lines ;;

Но это не работает, потому что разрывы строк представлены с помощью /r, а не/n.Я получаю список с одним элементом, который в основном выглядит следующим образом: ["abacinate\rabandon\rabase\rabash\rabate\rabbreviate\rabdicate"]

Каков наилучший способ изменить разрывы строк с /r на /n?Или есть способ прочитать в текстовом файле, чтобы я мог сказать ему сделать новый элемент в списке, когда он достигнет /r?

Ответы [ 2 ]

2 голосов
/ 26 апреля 2011

Технически, если ваш файл содержит записи, разделенные \r, а не записи, разделенные \n, это не текстовые файлы, состоящие из строк. Это файл в каком-то другом формате, который является текстовым форматом какой-то другой платформы. Поэтому преобразование файла в текстовый файл является очевидным решением.

Если вам нужна ваша программа для работы с символами новой строки, вам придется написать замену в input_line, потому что она имеет встроенное понятие встроенной строки (например, LF в unix, CR в MacOS до OSX, CR LF в DOS и Windows).

Поскольку вы все равно читаете весь файл в память, вы можете прочитать все это в Buffer. Обратите внимание, что Buffer.add_channel не будет работать, если вы заранее не знаете размер файла (и тогда вы можете также прочитать его в строку). Непроверенные:

let input_until_eof (chan : in_channel) : string =
  let buf = Buffer.create 10000 and tmp = String.create 4096 and n = ref 0 in
  while n := input chan tmp 0 (String.length tmp); n <> 0 do
    Buffer.add_substring buf tmp
  done;
  Buffer.contents buf
let tolerant_newline_regexp = Str.regexp "\r\\|\n\\|\013\|\010\013?"
let input_all_lines chan : string list =
  Str.split tolerant_newline_regexp (input_until_eof chan)

Если вы собираетесь проводить дальнейший анализ содержимого файла, используйте модуль Stream или Ocamllex.

2 голосов
/ 26 апреля 2011

Ну, вы, конечно, можете поиграть с заменой регулярным выражением в OCaml ... Например, вы можете прочитать весь файл в строку и выполнить подстановку. Однако, если ваш текстовый файл не изменяется (и я предполагаю, что в этом случае это не так, поскольку это просто большой список прилагательных), я бы использовал средства поиска и замены моего текстового редактора, чтобы выполнить замену в самом текстовом файле. , в отличие от попытки сделать это в вашей программе OCaml.

Если у вас установлен dos2unix, вы можете использовать его для перевода. Вы также можете использовать что-то вроде этого:

perl -pi -e 's/\r/\n/' filename

... использование этого подхода означает, что вы меняете файл один раз, и с этим вы покончили, а не всегда выполняете подстановку в вашей программе, которая при каждом запуске программы будет занимать немного больше времени.

...