Головная боль от Java-сканера
-
20-09-2019 - |
Вопрос
У меня есть текстовый файл, который выглядит как:
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 (хотя потенциально может и не иметь).
Как мне захватить каждый фрагмент name + rows с помощью сканера?Есть ли какой-нибудь элегантный способ обеспечить согласованность количества строк (и предоставить какую-то обратную связь, если они не согласованы)?
Я думаю, что мог бы быть удобный способ с умной спецификацией разделителя, но, похоже, я не могу заставить это работать.
Решение 2
Еще лучше, после полезный ответ на другой вопрос (спасибо Барт):
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;
}
Другие советы
Я бы сделал это простым способом.Захватите каждую строку как String
, и передайте его, скажем, через регулярное выражение, которое соответствует шаблону 1 или 0 с последующим пробелом.Если оно совпадает, рассматривайте его как строку.Если нет, относитесь к нему как к ярлыку с открытым текстом.Проверьте согласованность размеров строк и столбцов постфактум, убедившись, что массив данных каждой метки соответствует размеру массива данных первой метки.
Редактировать:Я не был осведомлен о Scanner
класс, хотя это звучит удобно.Я думаю, что основная идея все равно должна быть примерно той же ... используйте Scanner
чтобы проанализировать ваши входные данные и самостоятельно решить вопрос о размерах.
Кроме того, теоретически, вы могли бы создать регулярное выражение, которое соответствовало бы метке и всему массиву, хотя я не знаю, можете ли вы создать такое, которое гарантировало бы, что оно соответствует только наборам строк с одинаковым количеством значений в каждой строке.Но затем, чтобы настроить более автоматическую проверку, вам, вероятно, потребуется создать второе регулярное выражение, которое точно соответствует размеру массива первой записи, и использовать его для всех остальных.Я думаю, что это тот случай, когда лекарство хуже, чем болезнь.
Вам нужно будет открыть файл и перебирать каждую строку с помощью 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");
}
}
Вы также могли бы добавить еще один цикл, если вы не знаете ожидаемый размер для каждой строки, и ввести некоторую логику, чтобы найти наиболее распространенный размер, а затем выяснить, что не соответствует.Я не уверен в том, насколько сложной должна быть ваша проверка согласованности.