1 /* 2 * ModeShape (http://www.modeshape.org) 3 * See the COPYRIGHT.txt file distributed with this work for information 4 * regarding copyright ownership. Some portions may be licensed 5 * to Red Hat, Inc. under one or more contributor license agreements. 6 * See the AUTHORS.txt file in the distribution for a full listing of 7 * individual contributors. 8 * 9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape 10 * is licensed to you under the terms of the GNU Lesser General Public License as 11 * published by the Free Software Foundation; either version 2.1 of 12 * the License, or (at your option) any later version. 13 * 14 * ModeShape is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this software; if not, write to the Free 21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 23 */ 24 package org.modeshape.sequencer.text; 25 26 import java.util.Arrays; 27 import org.modeshape.common.util.CheckArg; 28 29 /** 30 * An text sequencer implementation that uses a {@link #setColumnStartPositions(String) list of column numbers} to split incoming 31 * rows into fixed-width columns. By default, this class treats each row as a single column. There is an implicit column start 32 * index of 0 for the first column. 33 * 34 * @see AbstractTextSequencer 35 */ 36 public class FixedWidthTextSequencer extends AbstractTextSequencer { 37 38 private int[] columnStartPositions = new int[] {}; 39 40 /** 41 * Set the column start positions. The column start positions are 0-based. Everything before the first start position is 42 * treated as the first column. 43 * <p> 44 * As an example, if the column start positions were {3, 6, 15} and the incoming stream was: 45 * 46 * <pre> 47 * 1 2 48 * 012345678901234567890 49 * supercallifragilistic 50 * expialidocious 51 * </pre> 52 * This sequencer would return the following rows: 53 * <pre> 54 * row 1: "sup", "erc", "allifragi", "listic" 55 * row 2: "exp:, "ial", "idocious" 56 * </pre> 57 * 58 * Note that there are only three columns returned in the second row, as there were not enough characters to reach the third 59 * start position. 60 * </p> 61 * 62 * @param columnStartPositions the column startPositions; may not be null 63 */ 64 public void setColumnStartPositions( int[] columnStartPositions ) { 65 CheckArg.isNotNull(columnStartPositions, "columnStartPositions"); 66 67 this.columnStartPositions = columnStartPositions; 68 Arrays.sort(columnStartPositions); 69 } 70 71 /** 72 * Set the column start positions from a list of column start positions concatenated into a single, comma-delimited string. 73 * 74 * @param commaDelimitedColumnStartPositions a list of column start positions concatenated into a single, comma-delimited 75 * string; may not be null 76 * @see #setColumnStartPositions(int[]) 77 */ 78 public void setColumnStartPositions( String commaDelimitedColumnStartPositions ) { 79 CheckArg.isNotNull(commaDelimitedColumnStartPositions, "commaDelimitedColumnStartPositions"); 80 81 String[] stringStartPositions = commaDelimitedColumnStartPositions.split(","); 82 int[] columnStartPositions = new int[stringStartPositions.length]; 83 84 for (int i = 0; i < stringStartPositions.length; i++) { 85 columnStartPositions[i] = Integer.valueOf(stringStartPositions[i]); 86 } 87 88 setColumnStartPositions(columnStartPositions); 89 } 90 91 @Override 92 protected String[] parseLine( String line ) { 93 assert line != null; 94 95 int columnCount = columnStartPositions.length + 1; 96 int currentPos = 0; 97 98 String[] columns = new String[columnCount]; 99 100 for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { 101 int endPos = columnIndex >= columnCount - 1 ? Integer.MAX_VALUE : columnStartPositions[columnIndex]; 102 String chunk = parseColumn(line, currentPos, endPos); 103 104 // The line was shorter than expected 105 if (chunk == null) { 106 assert columnIndex > 0 : "parseColumn failed to return the first column in string " + line; 107 108 String[] truncatedColumns = new String[columnIndex - 1]; 109 System.arraycopy(columns, 0, truncatedColumns, 0, columnIndex - 1); 110 return truncatedColumns; 111 } 112 columns[columnIndex] = chunk; 113 currentPos = endPos; 114 } 115 116 return columns; 117 } 118 119 private String parseColumn( String line, 120 int startPos, 121 int endPos ) { 122 int length = line.length(); 123 124 if (length < startPos) { 125 return null; 126 } 127 128 if (length < endPos) { 129 return line.substring(startPos); 130 } 131 132 return line.substring(startPos, endPos); 133 } 134 135 }