Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ on:
workflow_dispatch:

jobs:
build-8-11:
runs-on: ubuntu-22.04
build:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ '8', '9', '10', '11' ]
jdk: [ '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21' ]
name: JDK ${{ matrix.jdk }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
Expand All @@ -18,20 +18,4 @@ jobs:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
cache: 'maven'
- run: mvn verify -Dgpg.skip -Dmaven.compiler.source=6 -Dmaven.compiler.target=6

# JDK12+ no longer supports JDK6 as source/target
build-12-plus:
runs-on: ubuntu-22.04
strategy:
matrix:
jdk: [ '12', '13', '14', '15', '16', '17', '18' ]
name: JDK ${{ matrix.jdk }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
cache: 'maven'
- run: mvn verify -Dgpg.skip -Dmaven.compiler.source=7 -Dmaven.compiler.target=7
- run: mvn verify -Dgpg.skip
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
named-regexp [![GitHub release](https://img.shields.io/github/release/tony19/named-regexp.svg?maxAge=2592000)](https://github.com/tony19/named-regexp/releases/) [![Build](https://github.com/tony19/named-regexp/actions/workflows/ci.yml/badge.svg)](https://github.com/tony19/named-regexp/actions/workflows/ci.yml)
---

This lightweight library adds support for [named capture groups](http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#groupname) in Java 5/6 (and on Android).

This is a fork of the [named-regexp](http://code.google.com/p/named-regexp) project from Google Code (currently inactive).

This library backports [named capture groups](http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#groupname) from Java 7 to Java 5/6.

Usage
-----
You can use the same constructs for named capture groups from Java 7 (i.e., `(?<name>patt)`, etc.), as in the following example:
You can use the same constructs for named capture groups from Java 7
(i.e., `(?<name>patt)`, etc.), as in the following example:

```java
import com.google.code.regexp.Pattern;
Expand All @@ -29,15 +27,15 @@ Install

### Gradle
```gradle
implementation 'com.github.tony19:named-regexp:0.2.8'
implementation 'com.github.tony19:named-regexp:1.0.0'
```

### Maven
```xml
<dependency>
<groupId>com.github.tony19</groupId>
<artifactId>named-regexp</artifactId>
<version>0.2.8</version>
<version>1.0.0</version>
</dependency>
```

Expand All @@ -54,6 +52,10 @@ $ cd named-regexp
$ mvn package
```

To create Java 5/6 compatible bytecode, use JDK 11 or older to build this library.
The build automatically targets Java 8 (the minimum supported version) if using a
newer JDK to build.

Release
-------

Expand All @@ -65,7 +67,8 @@ $ ./release.sh

*Releases are deployed to https://repo1.maven.org/maven2/com/github/tony19/named-regexp/*

To release a `SNAPSHOT` (i.e., the version in `pom.xml` ends with `-SNAPSHOT`), run the following command:
To release a `SNAPSHOT` (i.e., the version in `pom.xml` ends with `-SNAPSHOT`),
run the following command:

```bash
$ mvn clean deploy
Expand All @@ -76,7 +79,7 @@ $ mvn clean deploy
License
-------

Copyright 2022 Anthony Trinh.
Copyright 2024 Anthony Trinh.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
16 changes: 15 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<packaging>jar</packaging>
<name>named-regexp</name>
<description>Named capturing groups for Java 5/6</description>
<version>0.2.9-SNAPSHOT</version>
<version>1.0.0-SNAPSHOT</version>
<url>https://github.com/tony19/named-regexp</url>

<licenses>
Expand Down Expand Up @@ -120,6 +120,20 @@
</build>

<profiles>
<profile>
<!--
If using JDK 12+, switch to Java 8 here (the minimum
supported version). Some users that mainly depend on newer
JDKS are still using this library for backward compatibility.
-->
<id>set-compiler-release</id>
<activation>
<jdk>[12,)</jdk>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
</profile>
<profile>
<id>release-sign-artifacts</id>
<activation>
Expand Down
28 changes: 25 additions & 3 deletions src/main/java/com/google/code/regexp/MatchResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,33 @@ public interface MatchResult extends java.util.regex.MatchResult {
public List<String> orderedGroups();

/**
* Returns the named capture groups
* Finds all named groups that exist in the input string
*
* @return the named capture groups
* @return a list of maps, each containing name-value matches
* (empty if no match found).
*
* Example:
* pattern: (?&lt;dote&gt;\d+).(?&lt;day&gt;\w+)
* input: 1 Sun foo bar 2 Mon foo
* output: [{"date":"1", "day":"Sun"}, {"date":"2", "day":"Mon"}]
*
* @since 1.0.0
*/
public List<Map<String, String>> namedGroupsList();

/**
* Returns a map of the pattern's named groups and indexes within the pattern.
*
* @return an unmodifiable map of group names to 1-based indexes
* (empty if named groups not found).
*
* Example:
* pattern: (a)(b)(?&lt;group1&gt;x)(c)(?&lt;group2&gt;y)
* output: {"group1": 3, "group2": 5}
*
* @since 1.0.0
*/
public List<Map<String, String>> namedGroups();
public Map<String, Integer> namedGroups();

/**
* Returns the input subsequence captured by the given group during the
Expand Down
33 changes: 32 additions & 1 deletion src/main/java/com/google/code/regexp/Matcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package com.google.code.regexp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -298,6 +300,33 @@ public String group(String groupName) {
return group(idx);
}

/**
* Returns a map of the pattern's named groups and indexes within the pattern.
*
* @return an unmodifiable map of group names to 1-based indexes
* (empty if named groups not found).
*
* Example:
* pattern: (a)(b)(?&lt;group1&gt;x)(c)(?&lt;group2&gt;y)
* output: {"group1": 3, "group2": 5}
*
* @since 1.0.0
*/
public Map<String, Integer> namedGroups() {
// Normally, this API isn't needed as this library is a backport
// of named groups, introduced in JDK7, but some users are
// using on this library in newer JDKs for whatever reason.
// https://github.com/tony19/named-regexp/issues/73
Map<String, Integer> result = new HashMap<String, Integer>();
Map<String, List<GroupInfo>> groupInfo = parentPattern.groupInfo();

for (Map.Entry<String, List<GroupInfo>> entry : groupInfo.entrySet()) {
// groupIndex() is 0-based and we need it 1-based for capture groups
result.put(entry.getKey(), entry.getValue().get(0).groupIndex() + 1);
}
return Collections.unmodifiableMap(result);
}

/**
* Finds all named groups that exist in the input string. This resets the
* matcher and attempts to match the input against the pre-specified
Expand All @@ -310,8 +339,10 @@ public String group(String groupName) {
* pattern: (?&lt;dote&gt;\d+).(?&lt;day&gt;\w+)
* input: 1 Sun foo bar 2 Mon foo
* output: [{"date":"1", "day":"Sun"}, {"date":"2", "day":"Mon"}]
*
* @since 1.0.0
*/
public List<Map<String, String>> namedGroups() {
public List<Map<String, String>> namedGroupsList() {
List<Map<String, String>> result = new ArrayList<Map<String, String>>();
List<String> groupNames = parentPattern.groupNames();

Expand Down
35 changes: 23 additions & 12 deletions src/test/java/com/google/code/regexp/MatcherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void beforeTest() {
}

@Test
public void testFindSucceedsInFindingTaret() {
public void testFindSucceedsInFindingTarget() {
assertTrue(P.matcher("abcfoo").find());
}

Expand Down Expand Up @@ -279,7 +279,7 @@ public void testOrderedGroupsHasMatchesInOrder() {

@Test
public void testNamedGroupsDoesNotThrowIndexOutOfBounds() {
// NamedMatcher.namedGroups() is used to get a map of
// Matcher#namedGroupsList() is used to get a map of
// group names to group values. This should ignore unnamed
// groups (exclude them from the map), but the unnamed
// groups were throwing off the function, causing it to
Expand All @@ -288,7 +288,7 @@ public void testNamedGroupsDoesNotThrowIndexOutOfBounds() {
Pattern p = Pattern.compile("(a)(?<foo>b)(?:c)(?<bar>d(?<named>x))");
Matcher m = p.matcher("abcdx");
try {
m.namedGroups();
m.namedGroupsList();
// verified here: IndexOutOfBoundsException did not occur
} catch (IndexOutOfBoundsException e) {
fail("IndexOutOfBoundsException should have been fixed");
Expand All @@ -300,7 +300,7 @@ public void testNamedGroupsGetsOnlyNamedGroups() {
Pattern p = Pattern.compile("(a)(?<foo>b)(?:c)(?<bar>d(?<named>x))");
Matcher m = p.matcher("abcdxyz");

List<Map<String, String>> list = m.namedGroups();
List<Map<String, String>> list = m.namedGroupsList();
assertEquals(1, list.size());

Map<String, String> map = list.get(0);
Expand All @@ -315,7 +315,7 @@ public void testNamedGroupsWithNoMatchGetsEmptyMap() {
Pattern p = Pattern.compile("(a)(?<foo>b)(?:c)(?<bar>d(?<named>x))");
Matcher m = p.matcher("nada");

List<Map<String, String>> list = m.namedGroups();
List<Map<String, String>> list = m.namedGroupsList();
assertEquals(0, list.size());
}

Expand Down Expand Up @@ -757,7 +757,7 @@ public void testNamedGroupsGetsAllMatchesInSingleGroup() {
Pattern pattern = Pattern.compile("(?<digit>\\d)(\\w)");
Matcher matcher = pattern.matcher("2foo3bar4");

final List<Map<String, String>> groups = matcher.namedGroups();
final List<Map<String, String>> groups = matcher.namedGroupsList();
assertEquals(2, groups.size());
assertEquals("2", groups.get(0).get("digit"));
assertEquals("3", groups.get(1).get("digit"));
Expand All @@ -768,7 +768,7 @@ public void testNamedGroupsGetsAllMatchesInMultipleGroups() {
Pattern pattern = Pattern.compile("(?<dayOfYear>\\d+).(?<dayName>\\w+)");
Matcher matcher = pattern.matcher("1 Sunday foo bar 2 Monday foo bar 3 Tuesday foo bar 4 Wednesday foo bar 5 Thursday foo bar 6 Friday foo bar 7 Saturday foo bar 8 Sunday foo bar 9 Monday foo bar 10 Tuesday foo bar ");

final List<Map<String, String>> groups = matcher.namedGroups();
final List<Map<String, String>> groups = matcher.namedGroupsList();
final String[] DAYS = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday"};
assertEquals(DAYS.length, groups.size());

Expand All @@ -784,15 +784,15 @@ public void testNamedGroupsReturnsEmptyListWhenNoGroupPresent() {
Pattern pattern = Pattern.compile("\\d+ no groups");
Matcher matcher = pattern.matcher("123 no groups");

final List<Map<String, String>> groups = matcher.namedGroups();
final List<Map<String, String>> groups = matcher.namedGroupsList();
assertTrue(groups.isEmpty());
}

// Specify 1 second timeout to account for potential infinite loop (Issue #16)
@Test(timeout=1000)
public void testNamedGroupsReturnsWhenMatchesEmptyString() {
com.google.code.regexp.Matcher matcher = com.google.code.regexp.Pattern.compile("(?<foo>.*)").matcher("bar");
final List<Map<String, String>> groups = matcher.namedGroups();
final List<Map<String, String>> groups = matcher.namedGroupsList();
assertEquals(1, groups.size());
assertEquals("bar", groups.get(0).get("foo"));
}
Expand All @@ -804,11 +804,22 @@ public void testNamedGroupsCanBeCalledMultipleTimes() {
final String url = "/teamDrawer/12345";

final Matcher matcher = Pattern.compile(regex).matcher(url);
final Integer count = matcher.namedGroups().size();
final Integer count = matcher.namedGroupsList().size();
assertEquals(Integer.valueOf(1), count);
final Integer mapCount = matcher.namedGroups().get(0).size();
final Integer mapCount = matcher.namedGroupsList().get(0).size();
assertEquals(Integer.valueOf(1), mapCount);
final String value = matcher.namedGroups().get(0).get("roomId");
final String value = matcher.namedGroupsList().get(0).get("roomId");
assertEquals("12345", value);
}

@Test
public void testMatcherNamedGroupsGetsMapsOfGroupIndexes() {
// Test compatibility with MatchResult#namedGroups added in JDK20
// https://github.com/tony19/named-regexp/issues/73
Pattern p = Pattern.compile("(b)(c)(?<named1>x)(d)(?<named2>y)");
MatchResult m = p.matcher("abcxdy");
Map<String, Integer> groupIndexes = m.namedGroups();
assertEquals(Integer.valueOf(3), groupIndexes.get("named1"));
assertEquals(Integer.valueOf(5), groupIndexes.get("named2"));
}
}