/* * ModeShape (http://www.modeshape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.modeshape.sequencer.text; import java.util.Arrays; import org.modeshape.common.util.CheckArg; /** * An text sequencer implementation that uses a {@link #setColumnStartPositions(String) list of column numbers} to split incoming * rows into fixed-width columns. By default, this class treats each row as a single column. There is an implicit column start * index of 0 for the first column. * * @see AbstractTextSequencer */ public class FixedWidthTextSequencer extends AbstractTextSequencer { private int[] columnStartPositions = new int[] {}; /** * Set the column start positions. The column start positions are 0-based. Everything before the first start position is * treated as the first column. * <p> * As an example, if the column start positions were {3, 6, 15} and the incoming stream was: * * <pre> * 1 2 * 012345678901234567890 * supercallifragilistic * expialidocious * </pre> * This sequencer would return the following rows: * <pre> * row 1: "sup", "erc", "allifragi", "listic" * row 2: "exp:, "ial", "idocious" * </pre> * * Note that there are only three columns returned in the second row, as there were not enough characters to reach the third * start position. * </p> * * @param columnStartPositions the column startPositions; may not be null */ public void setColumnStartPositions( int[] columnStartPositions ) { CheckArg.isNotNull(columnStartPositions, "columnStartPositions"); this.columnStartPositions = columnStartPositions; Arrays.sort(columnStartPositions); } /** * Set the column start positions from a list of column start positions concatenated into a single, comma-delimited string. * * @param commaDelimitedColumnStartPositions a list of column start positions concatenated into a single, comma-delimited * string; may not be null * @see #setColumnStartPositions(int[]) */ public void setColumnStartPositions( String commaDelimitedColumnStartPositions ) { CheckArg.isNotNull(commaDelimitedColumnStartPositions, "commaDelimitedColumnStartPositions"); String[] stringStartPositions = commaDelimitedColumnStartPositions.split(","); int[] columnStartPositions = new int[stringStartPositions.length]; for (int i = 0; i < stringStartPositions.length; i++) { columnStartPositions[i] = Integer.valueOf(stringStartPositions[i]); } setColumnStartPositions(columnStartPositions); } @Override protected String[] parseLine( String line ) { assert line != null; int columnCount = columnStartPositions.length + 1; int currentPos = 0; String[] columns = new String[columnCount]; for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { int endPos = columnIndex >= columnCount - 1 ? Integer.MAX_VALUE : columnStartPositions[columnIndex]; String chunk = parseColumn(line, currentPos, endPos); // The line was shorter than expected if (chunk == null) { assert columnIndex > 0 : "parseColumn failed to return the first column in string " + line; String[] truncatedColumns = new String[columnIndex - 1]; System.arraycopy(columns, 0, truncatedColumns, 0, columnIndex - 1); return truncatedColumns; } columns[columnIndex] = chunk; currentPos = endPos; } return columns; } private String parseColumn( String line, int startPos, int endPos ) { int length = line.length(); if (length < startPos) { return null; } if (length < endPos) { return line.substring(startPos); } return line.substring(startPos, endPos); } }