Головная боль сканера Java - PullRequest
       19

Головная боль сканера Java

1 голос
/ 09 октября 2009

У меня есть текстовый файл, который выглядит так:

name1
1 0 1 0 1
0 1 1 1 0
0 0 0 0 0
name2
1 0 1 0 1
0 0 1 1 0
0 0 0 0 1

, т. Е. Метка в виде открытого текста, за которой следуют несколько строк с 1/0, разделенными пробелами. Число строк в 1/0 является переменным, но каждая строка между любыми двумя конкретными метками должна иметь одинаковое количество 1/0 (хотя потенциально может и не иметь).

Как захватить каждый блок имен + строк с помощью сканера? Есть ли какой-нибудь элегантный способ обеспечить согласованность количества строк (и обеспечить некоторую обратную связь, если они не согласованы)?

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

Ответы [ 3 ]

1 голос
/ 10 октября 2009

Еще лучше, после полезного ответа на другой вопрос (спасибо Барт ):

static final String labelRegex="^\\s*\\w+$";
static final Pattern labelPattern = Pattern.compile(labelRegex, Pattern.MULTILINE);
Matcher labelMatcher = labelPattern.matcher("");

static final String stateRegex = "([10] )+[10]\\s+";
static final String statesRegex = "("+stateRegex+")+";
static final Pattern statesPattern = Pattern.compile(statesRegex, Pattern.MULTILINE);
Matcher stateMatcher = statesPattern.matcher("");

static final String chunkRegex = "(?="+labelRegex+")";
static final Pattern chunkPattern = Pattern.compile(chunkRegex,Pattern.MULTILINE);
Scanner chunkScan;

public void setSource(File source) {
    if(source!=null && source.canRead()) {
     try {
      chunkScan = new Scanner(new BufferedReader(new FileReader(source)));
      chunkScan.useDelimiter(chunkPattern);
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
}

public Map<String, List<GraphState>> next(int n) {
 Map<String,List<GraphState>> result = new LinkedHashMap<String,List<GraphState>>(n);
  String chunk, rows;
  int i=0;
  while (chunkScan.hasNext()&&i++<n) {
    chunk = chunkScan.next().trim();
    labelMatcher.reset(chunk);
    stateMatcher.reset(chunk);
   if (labelMatcher.find()&&stateMatcher.find()) {
    rows = stateMatcher.group().replace(" ", "");
    result.put(labelMatcher.group(), rowsToList(rows.split("\\n")));
   }
  }
  return result;
}
1 голос
/ 09 октября 2009

Я бы сделал это простым способом. Возьмите каждую строку как String и введите ее, скажем, через регулярное выражение, которое соответствует шаблону 1 или 0 с последующим пробелом. Если оно совпадает, относитесь к нему как к строке. Если нет, относитесь к нему как к текстовому ярлыку. Проверьте согласованность размера строки-столбца после факта, проверив, что массив данных каждой метки соответствует размеру массива данных первой метки.

РЕДАКТИРОВАТЬ: я не знал о классе Scanner, хотя это звучит удобно. Я думаю, что основная идея должна быть примерно такой же ... используйте Scanner для анализа ваших входных данных и решите вопрос о размерах самостоятельно.

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

0 голосов
/ 09 октября 2009

Вам нужно будет открыть файл и перебрать каждую строку с помощью readLine (), пока не дойдете до конца файла.

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

Когда вы обойдете это, вы можете проверить строку с помощью простого регулярного выражения, чтобы проверить, является ли оно именем метки. Если нет, разбейте строку на основе '' (пробела), и он вернется к вам в массиве. Затем проверьте размер на основе постоянного размера.

Базовый псевдокод:

int consistentSize = 5; // assume you have a size in mind

while ( (line = readLine()) != EOF)
{
    // check for if label, if it's a simple name, you won't really need a regex
    if (line == label)
    {
         // not sure if you want to do any consistency checking in here
    } else {
         String[] currLine = line.split(' ');
         bool consist = true;
         // now loop through currLine and do a check if each character is a number
         for (int i = 0; i < currLine.size(); i++)
         {
            // can't remember java function for this (isNum() I think)
            if (!currLine[i].isNum) { consist = false; break; }
         }
         // if got past this, the row has all numbers, therefore it is ok
            // could easily add another array to keep track of rows that didn't have valid numbers and suhc
         if (currLine.size() < consistentSize) System.out.println("row "+j + " is inconsistent");
    }
}

Вы также можете добавить еще один цикл, если вы не знаете ожидаемый размер для каждой строки, добавьте логику, чтобы найти наиболее распространенный размер, а затем выясните, что не соответствует. Я не уверен, насколько сложной должна быть ваша проверка согласованности.

...