Skip to content

Commit 2cdc632

Browse files
committed
Glob matcher added
1 parent 3cf84de commit 2cdc632

File tree

6 files changed

+140
-1
lines changed

6 files changed

+140
-1
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
}
88

99
group = "com.oxyggen.net"
10-
version = "1.0.7"
10+
version = "1.0.8"
1111

1212

1313
repositories {

src/main/kotlin/com/oxyggen/io/Path.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.oxyggen.io
22

3+
import java.nio.file.FileSystems
4+
35
/**
46
* Path object
57
*
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.oxyggen.matcher
2+
3+
class GlobMatcher(globPattern: String) : RegexMatcher(globToRegexPattern(globPattern)) {
4+
5+
companion object {
6+
/**
7+
* Converts glob pattern to regular expression
8+
* Java source found on https://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns
9+
* created by Neil Traft, so I've converted to Kotlin code
10+
* @param globPattern the glob pattern
11+
* @return regular expression string
12+
*/
13+
14+
private fun globToRegexPattern(globPattern: String): String {
15+
var result = ""
16+
17+
var index = 0
18+
val groupIndex = mutableListOf<Int>()
19+
val classIndex = mutableListOf<Int>()
20+
21+
while (index < globPattern.length) {
22+
val ch = globPattern[index]
23+
24+
result += when (ch) {
25+
'\\' ->
26+
if (++index >= globPattern.length) { // If it's last character, not an escape char
27+
ch
28+
} else {
29+
val nch = globPattern[index]
30+
when (nch) {
31+
',' -> nch // Escape character not needed
32+
'Q', 'E' -> "\\\\$nch" // \Q \E are special delimiters in regex for quoting literals
33+
else -> "\\$nch" // Escape any other character
34+
}
35+
}
36+
37+
'*' ->
38+
if (classIndex.isEmpty()) {
39+
".*"
40+
} else {
41+
"*"
42+
}
43+
44+
'?' ->
45+
if (classIndex.isEmpty()) {
46+
"."
47+
} else {
48+
"?"
49+
}
50+
51+
'[' -> {
52+
classIndex.add(index)
53+
"["
54+
}
55+
56+
']' -> {
57+
classIndex.dropLast(1)
58+
"]"
59+
}
60+
61+
'{' -> {
62+
groupIndex.add(index)
63+
"("
64+
}
65+
66+
'}' -> {
67+
groupIndex.dropLast(1)
68+
")"
69+
}
70+
71+
'.', '(', ')', '+', '|', '^', '$', '@', '%' ->
72+
if (classIndex.isEmpty() || (classIndex.last() + 1 == index && ch == '^')) {
73+
"\\$ch"
74+
} else {
75+
ch
76+
}
77+
78+
'!' ->
79+
if (classIndex.isNotEmpty() && classIndex.last() + 1 == index) {
80+
"^"
81+
} else {
82+
"!"
83+
}
84+
85+
',' ->
86+
if (groupIndex.isNotEmpty()) {
87+
"|"
88+
} else {
89+
","
90+
}
91+
92+
else -> ch
93+
}
94+
95+
index++
96+
}
97+
98+
return result
99+
}
100+
}
101+
102+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.oxyggen.matcher
2+
3+
abstract class Matcher() {
4+
abstract fun matches(str: CharSequence): Boolean
5+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.oxyggen.matcher
2+
3+
open class RegexMatcher(regexPattern: String) : Matcher() {
4+
5+
private val regex: Regex = Regex(regexPattern)
6+
7+
open fun toRegex() = regex
8+
9+
override fun matches(str: CharSequence): Boolean = regex.matches(str)
10+
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.oxyggen.matcher
2+
3+
import org.junit.jupiter.api.Assertions
4+
import org.junit.jupiter.api.Test
5+
6+
internal class GlobMatcherTest {
7+
@Test
8+
fun `glob to regexp tester`() {
9+
val gm = GlobMatcher("*/*.txt")
10+
11+
println(gm.toRegex().pattern)
12+
13+
Assertions.assertTrue(gm.matches("hello.txt"))
14+
Assertions.assertFalse(gm.matches("hello.txt.exe"))
15+
16+
Assertions.assertTrue(gm.matches("abc/hello.txt"))
17+
}
18+
19+
}

0 commit comments

Comments
 (0)