2015-04-09 2 views
0

У меня есть CSV файл с нестандартизированным содержанием, это выглядит примерно так:Манипулирование CSV файл с нестандартизированным содержанием

John, 001 
01/01/2015, hamburger 
02/01/2015, pizza 
03/01/2015, ice cream 
Mary, 002 
01/01/2015, hamburger 
02/01/2015, pizza 
John, 003 
04/01/2015, chocolate 

Теперь, что я пытаюсь сделать, это написать логику java, чтобы отделить их. Мне хотелось бы «John, 001» в качестве заголовка и поставить все строки под Джоном, прежде чем Мэри станет Джоном.

Возможно ли это? Или я должен просто сделать это вручную?

Edit:
Для ввода, даже если он не стандартизирован, заметная картина является то, что строка, не имеют имен будет всегда начинается с датой.
Мой выходной объект был бы java-объектом, где я могу хранить его в базе данных в конечном итоге в формате ниже.

Name, hamburger, pizza, ice cream, chocolate 
John, 01/01/2015, 02/01/2015, 03/01/2015, NA 
Mary, 01/01/2015, 02/01/2015, NA, NA 
John, NA, NA, NA, 04/01/2015 
+0

Итак, каждая строка, начинающаяся с имени, знаменует начало нового CSV-файла? –

+1

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

+0

@ Тичодрома да, вы правы. – user486174

ответ

2

Вы можете просто прочитать файл в список

List<String> lines = Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8); 

Затем итерация по списку и разделить их на разыскиваемые разделители (",").

Теперь вы можете просто использовать блоки if-else или switch для проверки конкретных записей.

List<DataObject> objects = new ArrayList<>(); 
DataObject dataObject = null; 
for(String s : lines) { 
    String [] splitLine = s.split(","); 
    if(splitLine[0].matches("(\d{2}\/){2}\d{4}")) { 
     // We found a data 
     if(dataObject != null && splitLine.length == 2) { 
      String date = splitLine[0]; 
      String dish = splitLine[1]; 
      dataObject.add(date, dish); 
     } else { 
      // Handle error 
     } 
    } else if(splitLine.length == 2) { 
     // We can create a new data object 
     if(dataObject != null) { 
      objects.add(dataObject); 
     } 
     String name = splitLine[0]; 
     String id = splitLine[1]; 
     dataObject = new DataObject(name, id); 
    } else { 
     // Handle error 
    } 
} 

Теперь вы можете сортировать их в своих конкретных категориях.

Редактировать: Изменен цикл и добавлено регулярное выражение (что может быть не оптимальным) для сопоставления строк даты и использования их, чтобы решить, добавлять ли их к последнему объекту данных.

Класс DataObject может содержать структуры данных, содержащие даты/блюда. Когда CSV анализируется, вы можете перебирать список объектов и делать все, что хотите. Я надеюсь, что этот ответ поможет :)

+0

Это не отвечает на вопрос OP - вам придется изменить его, чтобы посмотреть на splitLine [0] и определить, похоже ли это на дату. Если это дата, то она добавляет данные предыдущего элемента, в противном случае это начало нового элемента. –

+0

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

+0

У вас есть жесткое кодирование элементов данных в коде. Например, «Джон». Я думаю, что это не то, что нужно. –

2

Если я правильно понял, то спецификации:

  • ввод текста, одна запись в строке (поля используется запятая)
  • 2 вида записей:
    • заголовки, состоящая из имени и номера (номер игнорируется)
    • фактических записей, состоящие из даты и еды
  • выход должен содержать:
    • один заголовок, содержащий постоянную Имени, а питание в порядке встречаемости
    • на записи на имя, состоящее с именем и даты, соответствующих приемы пищи - отсутствующее поле будет иметь NA постоянной строка
  • мы предполагаем, что мы никогда не получим на имя те же даты для различных входных записей.

Алгоритм в псевдокоде:

Data structures : 
one list of struct< string name, hash< int meal index, date> > for the names : base 
one list of strings for the meals : meals 

Code : 

name = null 
iname = -1 
Loop per input lines { 
    if first field is date { 
    if name == null { 
     throw Exception("incorrect structure"); 
    } 
    meal = second field 
    look for index of meal in meals 
    if not found { 
     index = len(meals); 
     add meal at end of list meals 
    } 
    base[iname].hash[index] = date 
    } 
    else { 
    name = first field 
    iname += 1 
    add a new struc { name, empty hash } at end of list base 
    } 
} 
close input file 
open output file 
// headers 
print "names" 
for meal in meals { 
    print ",", meal 
} 
print newline 
for (i=0; i<=iname; i++) { 
    print base[i].name 
    for meal in meals { 
    look for meal in base[i].hash.keys 
    if found { 
     print ",", base[i].hash[meal] 
    } 
    else { 
     print ",NA" 
    } 
    } 
    print newline 
} 
close output file 

Просто его код в правильной Java и вернуться сюда, если у вас есть какие-либо проблемы.

0

Используйте uniVocity-parsers, чтобы обработать это для вас. Он поставляется с процессором рядовых деталей.

// 1st, Create a RowProcessor to process all "detail" elements (dates/ingredients) 
ObjectRowListProcessor detailProcessor = new ObjectRowListProcessor(); 

// 2nd, Create MasterDetailProcessor to identify whether or not a row is the master row (first value of the row is a name, second is an integer). 
MasterDetailListProcessor masterRowProcessor = new MasterDetailListProcessor(RowPlacement.TOP, detailProcessor) { 
    @Override 
    protected boolean isMasterRecord(String[] row, ParsingContext context) { 
     try{ 
      //tries to convert the second value of the row to an Integer. 
      Integer.parseInt(String.valueOf(row[1])); 
      return true; 
     } catch(NumberFormatException ex){ 
      return false; 
     } 
    } 
}; 

CsvParserSettings parserSettings = new CsvParserSettings(); 

// Set the RowProcessor to the masterRowProcessor. 
parserSettings.setRowProcessor(masterRowProcessor); 

CsvParser parser = new CsvParser(parserSettings); 
parser.parse(new FileReader(yourFile)); 

// Here we get the MasterDetailRecord elements. 
List<MasterDetailRecord> rows = masterRowProcessor.getRecords(); 

// Each master record has one master row and multiple detail rows. 
MasterDetailRecord masterRecord = rows.get(0); 
Object[] masterRow = masterRecord.getMasterRow(); 
List<Object[]> detailRows = masterRecord.getDetailRows(); 

Раскрытие информации: Я являюсь автором этой библиотеки. Это бесплатно и бесплатно (лицензия Apache V2.0).

Смежные вопросы