У меня возникли проблемы с некоторыми основными операциями ввода-вывода с использованием Clojure. У меня есть текстовый файл, который мне нужно прочитать, разделенный с помощью "|" символ и введите в список для последующей обработки. Вот содержимое моего текстового файла:
1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533
И вот мой текущий код:
((defn -main []
(println "Enter an option: \n")
(let [choice (read-line)]
(cond (= choice "1")
(let [cust-contents (slurp "file.txt")
nums-as-strings (clojure.string/split cust-contents #"|")
numbers (map read-string nums-as-strings)]
(print numbers)
)
)
) ) )
(-main)
Я бы подумал, что этот код работает, однако вот ошибка, которую я получаю при запуске моей программы:
(; Execution error at user/eval7923$-main (REPL:11).
; EOF while reading
Может ли кто-нибудь указать мне, где я ошибся и как это исправить?





Во-первых, у вас не должно быть 2 левых скобок подряд, например ((defn ....
Кроме того, парсинг CSV имеет множество библиотек, позволяющих избавиться от нудного изобретения велосипеда. Мой фаворит проиллюстрирован ниже:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require
[tupelo.csv :as csv]))
(verify
; ***** NOTE ***** most CSV has a header line, which is added below for convenience!
(let [data-str "id|name|address|phone
1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533 "
entity-maps (csv/csv->entities data-str {:separator \|})]
(is= entity-maps
[{:address "123 Here Street", :id "1", :name "John Smith", :phone "456-4567"}
{:address "43 Rose Court Street", :id "2", :name "Sue Jones", :phone "345-7867"}
{:address "165 Happy Lane", :id "3", :name "Fan Yuhong", :phone "345-4533"}])))
Этот модульный тест не включает часть чтения файлов, поскольку это только усложняет модульный тест.
Приведенное выше решение основано на моем любимом шаблонном проекте, в конце которого также есть список источников документации.
Вы можете найти исходный код для tupelo.csv а также модульные тесты.
Чтобы прояснить ваш код, вот очищенная версия:
(verify
(let [data-str "1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533 "
data-lines (str/split-lines data-str)
token-table-str (vec (for [line data-lines]
(let [token-strs (str/split line #"\|")]
(mapv str/trim token-strs))))]
(is= token-table-str
[["1" "John Smith" "123 Here Street" "456-4567"]
["2" "Sue Jones" "43 Rose Court Street" "345-7867"]
["3" "Fan Yuhong" "165 Happy Lane" "345-4533"]])))
Обратите внимание, что я не анализировал данные после стадии String.
Эта ошибка на самом деле возникает, когда вы вызываете read-string с аргументом " ".
А откуда этот " "? Вы использовали неправильное регулярное выражение в clojure.string/split, вы должны использовать #"\|" вместо #"|".
И даже тогда вы не можете вызывать read-string на всем, так как вскоре он снова вылетит, пытаясь разобрать "456-4567".
Кроме того, закрывающие скобки принадлежат одной и той же строке.
Если ваш файл содержит символы новой строки, вам понадобится clojure.string/split-lines , а если вы также реализуете 2 Display Product Table, 3. Display Sales Table и так далее (я знаю контекст для этого кода), case будет лучше, чем cond.
Вот ваш код с некоторыми улучшениями:
(ns homework.core
(:require [clojure.string :as s])
(:gen-class))
(defn -main []
(println "Enter an option: \n")
(let [choice (read-line)]
(case choice
"1" (->> (s/split-lines (slurp "file.txt"))
(mapv #(s/split % #"\|"))
println)
"Wrong number")))
(-main)
Добавьте [clojure-csv/clojure-csv "2.0.1"] к своим lein зависимостям.
Сделайте lein deps, чтобы установить его.
Поместить в файл, например. "/home/me/test.csv"
1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533
(ns csvread
(:require [clojure-csv.core :as csv]))
(defn parse-table [file]
(csv/parse-csv (slurp file) :delimiter \|))
(defn parse-table-from-string [s]
(csv/parse-csv s :delimiter \|))
Примените это:
(parse-table "/home/me/test.csv")
;; => (["1" "John Smith" "123 Here Street" "456-4567"]
;; ["2" "Sue Jones" "43 Rose Court Street" "345-7867"]
;; ["3" "Fan Yuhong" "165 Happy Lane" "345-4533 "])
(def s "1|John Smith|123 Here Street|456-4567
2|Sue Jones|43 Rose Court Street|345-7867
3|Fan Yuhong|165 Happy Lane|345-4533")
(parse-table-from-string s)