From 8db5925eb36346d861a2b296f89a3db08afcd900 Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 16:34:36 -0600 Subject: [PATCH 1/6] feat!: rename MatchResult#namedGroups to #namedGroupsList JDK20 introduced their own MatchResult#namedGroups, so we have to rename to avoid the naming conflict. fix #73 --- .../com/google/code/regexp/MatchResult.java | 28 ++++++++++++++-- .../java/com/google/code/regexp/Matcher.java | 33 ++++++++++++++++++- .../com/google/code/regexp/MatcherTest.java | 33 ++++++++++++------- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/google/code/regexp/MatchResult.java b/src/main/java/com/google/code/regexp/MatchResult.java index 5a82838..4195f63 100644 --- a/src/main/java/com/google/code/regexp/MatchResult.java +++ b/src/main/java/com/google/code/regexp/MatchResult.java @@ -37,11 +37,33 @@ public interface MatchResult extends java.util.regex.MatchResult { public List 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: (?<dote>\d+).(?<day>\w+) + * input: 1 Sun foo bar 2 Mon foo + * output: [{"date":"1", "day":"Sun"}, {"date":"2", "day":"Mon"}] + * + * @since 1.0.0 + */ + public List> 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)(?<group1>x)(c)(?<group2>y) + * output: {"group1": 3, "group2": 5} + * + * @since 1.0.0 */ - public List> namedGroups(); + public Map namedGroups(); /** * Returns the input subsequence captured by the given group during the diff --git a/src/main/java/com/google/code/regexp/Matcher.java b/src/main/java/com/google/code/regexp/Matcher.java index 9b6b1b1..61fc03f 100644 --- a/src/main/java/com/google/code/regexp/Matcher.java +++ b/src/main/java/com/google/code/regexp/Matcher.java @@ -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; @@ -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)(?<group1>x)(c)(?<group2>y) + * output: {"group1": 3, "group2": 5} + * + * @since 1.0.0 + */ + public Map 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 result = new HashMap(); + Map> groupInfo = parentPattern.groupInfo(); + + for (Map.Entry> 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 @@ -310,8 +339,10 @@ public String group(String groupName) { * pattern: (?<dote>\d+).(?<day>\w+) * input: 1 Sun foo bar 2 Mon foo * output: [{"date":"1", "day":"Sun"}, {"date":"2", "day":"Mon"}] + * + * @since 1.0.0 */ - public List> namedGroups() { + public List> namedGroupsList() { List> result = new ArrayList>(); List groupNames = parentPattern.groupNames(); diff --git a/src/test/java/com/google/code/regexp/MatcherTest.java b/src/test/java/com/google/code/regexp/MatcherTest.java index bbc8095..a7758f2 100644 --- a/src/test/java/com/google/code/regexp/MatcherTest.java +++ b/src/test/java/com/google/code/regexp/MatcherTest.java @@ -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 @@ -288,7 +288,7 @@ public void testNamedGroupsDoesNotThrowIndexOutOfBounds() { Pattern p = Pattern.compile("(a)(?b)(?:c)(?d(?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"); @@ -300,7 +300,7 @@ public void testNamedGroupsGetsOnlyNamedGroups() { Pattern p = Pattern.compile("(a)(?b)(?:c)(?d(?x))"); Matcher m = p.matcher("abcdxyz"); - List> list = m.namedGroups(); + List> list = m.namedGroupsList(); assertEquals(1, list.size()); Map map = list.get(0); @@ -315,7 +315,7 @@ public void testNamedGroupsWithNoMatchGetsEmptyMap() { Pattern p = Pattern.compile("(a)(?b)(?:c)(?d(?x))"); Matcher m = p.matcher("nada"); - List> list = m.namedGroups(); + List> list = m.namedGroupsList(); assertEquals(0, list.size()); } @@ -757,7 +757,7 @@ public void testNamedGroupsGetsAllMatchesInSingleGroup() { Pattern pattern = Pattern.compile("(?\\d)(\\w)"); Matcher matcher = pattern.matcher("2foo3bar4"); - final List> groups = matcher.namedGroups(); + final List> groups = matcher.namedGroupsList(); assertEquals(2, groups.size()); assertEquals("2", groups.get(0).get("digit")); assertEquals("3", groups.get(1).get("digit")); @@ -768,7 +768,7 @@ public void testNamedGroupsGetsAllMatchesInMultipleGroups() { Pattern pattern = Pattern.compile("(?\\d+).(?\\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> groups = matcher.namedGroups(); + final List> groups = matcher.namedGroupsList(); final String[] DAYS = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday"}; assertEquals(DAYS.length, groups.size()); @@ -784,7 +784,7 @@ public void testNamedGroupsReturnsEmptyListWhenNoGroupPresent() { Pattern pattern = Pattern.compile("\\d+ no groups"); Matcher matcher = pattern.matcher("123 no groups"); - final List> groups = matcher.namedGroups(); + final List> groups = matcher.namedGroupsList(); assertTrue(groups.isEmpty()); } @@ -792,7 +792,7 @@ public void testNamedGroupsReturnsEmptyListWhenNoGroupPresent() { @Test(timeout=1000) public void testNamedGroupsReturnsWhenMatchesEmptyString() { com.google.code.regexp.Matcher matcher = com.google.code.regexp.Pattern.compile("(?.*)").matcher("bar"); - final List> groups = matcher.namedGroups(); + final List> groups = matcher.namedGroupsList(); assertEquals(1, groups.size()); assertEquals("bar", groups.get(0).get("foo")); } @@ -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)(?x)(d)(?y)"); + MatchResult m = p.matcher("abcxdy"); + Map groupIndexes = m.namedGroups(); + assertEquals(Integer.valueOf(3), groupIndexes.get("named1")); + assertEquals(Integer.valueOf(5), groupIndexes.get("named2")); + } } From 4924e88ecdd30fcfa26723a6fcf88b183f06194f Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 16:38:05 -0600 Subject: [PATCH 2/6] chore: fix typo --- src/test/java/com/google/code/regexp/MatcherTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/google/code/regexp/MatcherTest.java b/src/test/java/com/google/code/regexp/MatcherTest.java index a7758f2..1493fe5 100644 --- a/src/test/java/com/google/code/regexp/MatcherTest.java +++ b/src/test/java/com/google/code/regexp/MatcherTest.java @@ -39,7 +39,7 @@ public void beforeTest() { } @Test - public void testFindSucceedsInFindingTaret() { + public void testFindSucceedsInFindingTarget() { assertTrue(P.matcher("abcfoo").find()); } From 313969142f220a0c980f49bdc98e8968f9cf02bc Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 16:48:02 -0600 Subject: [PATCH 3/6] chore: bump major version --- README.md | 6 +++--- pom.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 43b704a..2a64ea8 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Install ### Gradle ```gradle -implementation 'com.github.tony19:named-regexp:0.2.8' +implementation 'com.github.tony19:named-regexp:1.0.0' ``` ### Maven @@ -37,7 +37,7 @@ implementation 'com.github.tony19:named-regexp:0.2.8' com.github.tony19 named-regexp - 0.2.8 + 1.0.0 ``` @@ -76,7 +76,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. diff --git a/pom.xml b/pom.xml index c88cba2..323f2cd 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ jar named-regexp Named capturing groups for Java 5/6 - 0.2.9-SNAPSHOT + 1.0.0-SNAPSHOT https://github.com/tony19/named-regexp From 021a50e133b90c06edbc3c7ac3c66bcc5bfc37fc Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 17:29:39 -0600 Subject: [PATCH 4/6] ci: add jdk 19-21 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78c9b96..9a54970 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - jdk: [ '12', '13', '14', '15', '16', '17', '18' ] + jdk: [ '12', '13', '14', '15', '16', '17', '18', '19', '20', '21' ] name: JDK ${{ matrix.jdk }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 From a46f1bc8fbef4ca2443e35879f9f760df82a086b Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 17:52:58 -0600 Subject: [PATCH 5/6] build: compile java 8 for JDK 12 or higher --- .github/workflows/ci.yml | 24 ++++-------------------- pom.xml | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a54970..051e116 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 @@ -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', '19', '20', '21' ] - 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 \ No newline at end of file + - run: mvn verify -Dgpg.skip diff --git a/pom.xml b/pom.xml index 323f2cd..82c2816 100644 --- a/pom.xml +++ b/pom.xml @@ -120,6 +120,20 @@ + + + set-compiler-release + + [12,) + + + 8 + + release-sign-artifacts From 9552147311f0f2b88404d9a2d4ebadf96abce4cc Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Sat, 20 Jan 2024 18:11:45 -0600 Subject: [PATCH 6/6] chore: add note about JDK and bytecode compatibility --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a64ea8..640f46e 100644 --- a/README.md +++ b/README.md @@ -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., `(?patt)`, etc.), as in the following example: +You can use the same constructs for named capture groups from Java 7 +(i.e., `(?patt)`, etc.), as in the following example: ```java import com.google.code.regexp.Pattern; @@ -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 ------- @@ -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