diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/ArrayFieldSetMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/ArrayFieldSetMapper.java new file mode 100644 index 000000000..2151b4779 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/ArrayFieldSetMapper.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011-2012 the original author or authors. + * + * 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.springframework.batch.item.file.mapping; + +import org.springframework.batch.item.file.transform.FieldSet; +import org.springframework.validation.BindException; + +/** + * A basic array mapper, returning the values backing a fieldset. + * Useful for reading the Strings resulting from the line tokenizer without having to + * deal with a {@link FieldSet} object. + * + * @author Costin Leau + */ +public class ArrayFieldSetMapper implements FieldSetMapper { + + public String[] mapFieldSet(FieldSet fieldSet) throws BindException { + return fieldSet.getValues(); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RegexLineTokenizer.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RegexLineTokenizer.java new file mode 100644 index 000000000..29ca7e6d6 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RegexLineTokenizer.java @@ -0,0 +1,89 @@ +/* + * Copyright 2006-2012 the original author or authors. + * + * 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.springframework.batch.item.file.transform; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.util.Assert; + +/** + * Line-tokenizer using a regular expression to filter out data (by using matching and non-matching groups). + * Consider the following regex which picks only the first and last name (notice the non-matching group in the middle): + *
+ * (.*?)(?: .*)* (.*) 
+ * 
+ * For the names: + * + * + * the output will be: + * + * + * An empty list is returned, in case of a non-match. + * + * @see Matcher#group(int) + * @author Costin Leau + */ +public class RegexLineTokenizer extends AbstractLineTokenizer { + + private Pattern pattern; + + @Override + protected List doTokenize(String line) { + Matcher matcher = pattern.matcher(line); + boolean matchFound = matcher.find(); + + if (matchFound) { + List tokens = new ArrayList(matcher.groupCount()); + for (int i = 1; i <= matcher.groupCount(); i++) { + tokens.add(matcher.group(i)); + } + return tokens; + } + return Collections.emptyList(); + } + + /** + * Sets the regex pattern to use. + * + * @param pattern Regular Expression pattern + */ + public void setPattern(Pattern pattern) { + Assert.notNull(pattern, "a non-null pattern is required"); + this.pattern = pattern; + } + + /** + * Sets the regular expression to use. + * + * @param regex regular expression (as a String) + */ + public void setRegex(String regex) { + Assert.hasText(regex, "a valid regex is required"); + this.pattern = Pattern.compile(regex); + } +} \ No newline at end of file diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/RegexLineTokenizerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/RegexLineTokenizerTests.java new file mode 100644 index 000000000..a2e72ae7f --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/RegexLineTokenizerTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006-2012 the original author or authors. + * + * 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.springframework.batch.item.file.transform; + +import java.util.List; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RegexLineTokenizerTests { + + private RegexLineTokenizer tokenizer = new RegexLineTokenizer(); + + @Test + public void testCapturingGroups() { + String line = "Liverpool, England: 53d 25m 0s N 3d 0m 0s"; + tokenizer.setRegex("([a-zA-Z]+), ([a-zA-Z]+): ([0-9]+). ([0-9]+). ([0-9]+). ([A-Z]) ([0-9]+). ([0-9]+). ([0-9]+)."); + List tokens = tokenizer.doTokenize(line); + assertEquals(9, tokens.size()); + assertEquals("England", tokens.get(1)); + assertEquals("3", tokens.get(6)); + } + + @Test + public void testNonCapturingGroups() { + String line = "Graham James Edward Miller"; + tokenizer.setRegex("(.*?)(?: .*)* (.*)"); + List tokens = tokenizer.doTokenize(line); + assertEquals(2, tokens.size()); + assertEquals("Graham", tokens.get(0)); + assertEquals("Miller", tokens.get(1)); + } + + @Test + public void testNoMatch() { + tokenizer.setRegex("([0-9]+)."); + List tokens = tokenizer.doTokenize("noNumber"); + assertEquals(0, tokens.size()); + } +}