"glob" 유형 패턴에 대해 java.util.regex와 동등한 것이 있습니까?
Java에서 "글로브" 유형의 매칭을 수행하기 위한 표준 라이브러리(가능하면 Apache Commons 또는 유사한 비바이러스 라이브러리)가 있습니까?을 한 번 "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" "Perl" 을 모두 변경했습니다..
\.
", ",*
.*
및 " " " "?
.
그 궁금해요그런 것도 있지만, 누군가 저를 위해 그 일을 해줬는지 궁금해요.
유사한 질문: glob 식에서 regex 생성
Globing은 Java 7에서도 구현될 예정입니다.
내장된 것은 없지만, 글로벌한 것을 regex로 변환하는 것은 매우 간단합니다.
public static String createRegexFromGlob(String glob)
{
String out = "^";
for(int i = 0; i < glob.length(); ++i)
{
final char c = glob.charAt(i);
switch(c)
{
case '*': out += ".*"; break;
case '?': out += '.'; break;
case '.': out += "\\."; break;
case '\\': out += "\\\\"; break;
default: out += c;
}
}
out += '$';
return out;
}
이 방법이 도움이 됩니다만, 글로벌 스탠다드가 있는지는 잘 모르겠습니다.
Paul Tomblin에 의한 갱신:glob 변환을 하는 perl 프로그램을 찾아서 Java에 적응하면 다음과 같이 됩니다.
private String convertGlobToRegEx(String line)
{
LOG.info("got line [" + line + "]");
line = line.trim();
int strLen = line.length();
StringBuilder sb = new StringBuilder(strLen);
// Remove beginning and ending * globs because they're useless
if (line.startsWith("*"))
{
line = line.substring(1);
strLen--;
}
if (line.endsWith("*"))
{
line = line.substring(0, strLen-1);
strLen--;
}
boolean escaping = false;
int inCurlies = 0;
for (char currentChar : line.toCharArray())
{
switch (currentChar)
{
case '*':
if (escaping)
sb.append("\\*");
else
sb.append(".*");
escaping = false;
break;
case '?':
if (escaping)
sb.append("\\?");
else
sb.append('.');
escaping = false;
break;
case '.':
case '(':
case ')':
case '+':
case '|':
case '^':
case '$':
case '@':
case '%':
sb.append('\\');
sb.append(currentChar);
escaping = false;
break;
case '\\':
if (escaping)
{
sb.append("\\\\");
escaping = false;
}
else
escaping = true;
break;
case '{':
if (escaping)
{
sb.append("\\{");
}
else
{
sb.append('(');
inCurlies++;
}
escaping = false;
break;
case '}':
if (inCurlies > 0 && !escaping)
{
sb.append(')');
inCurlies--;
}
else if (escaping)
sb.append("\\}");
else
sb.append("}");
escaping = false;
break;
case ',':
if (inCurlies > 0 && !escaping)
{
sb.append('|');
}
else if (escaping)
sb.append("\\,");
else
sb.append(",");
break;
default:
escaping = false;
sb.append(currentChar);
}
}
return sb.toString();
}
이 답변이 저를 올바른 방향으로 이끌었기 때문에, 저는 제 답변을 만들기보다는 이 답변으로 편집하고 있습니다.
여기 계신 모든 분들께 감사의 말씀을 드립니다.이전 답변보다 더 포괄적인 변환을 작성했습니다.
/**
* Converts a standard POSIX Shell globbing pattern into a regular expression
* pattern. The result can be used with the standard {@link java.util.regex} API to
* recognize strings which match the glob pattern.
* <p/>
* See also, the POSIX Shell language:
* http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01
*
* @param pattern A glob pattern.
* @return A regex pattern to recognize the given glob pattern.
*/
public static final String convertGlobToRegex(String pattern) {
StringBuilder sb = new StringBuilder(pattern.length());
int inGroup = 0;
int inClass = 0;
int firstIndexInClass = -1;
char[] arr = pattern.toCharArray();
for (int i = 0; i < arr.length; i++) {
char ch = arr[i];
switch (ch) {
case '\\':
if (++i >= arr.length) {
sb.append('\\');
} else {
char next = arr[i];
switch (next) {
case ',':
// escape not needed
break;
case 'Q':
case 'E':
// extra escape needed
sb.append('\\');
default:
sb.append('\\');
}
sb.append(next);
}
break;
case '*':
if (inClass == 0)
sb.append(".*");
else
sb.append('*');
break;
case '?':
if (inClass == 0)
sb.append('.');
else
sb.append('?');
break;
case '[':
inClass++;
firstIndexInClass = i+1;
sb.append('[');
break;
case ']':
inClass--;
sb.append(']');
break;
case '.':
case '(':
case ')':
case '+':
case '|':
case '^':
case '$':
case '@':
case '%':
if (inClass == 0 || (firstIndexInClass == i && ch == '^'))
sb.append('\\');
sb.append(ch);
break;
case '!':
if (firstIndexInClass == i)
sb.append('^');
else
sb.append('!');
break;
case '{':
inGroup++;
sb.append('(');
break;
case '}':
inGroup--;
sb.append(')');
break;
case ',':
if (inGroup > 0)
sb.append('|');
else
sb.append(',');
break;
default:
sb.append(ch);
}
}
return sb.toString();
}
그리고 유닛은 그것이 작동함을 증명하기 위해 테스트를 실시합니다.
/**
* @author Neil Traft
*/
public class StringUtils_ConvertGlobToRegex_Test {
@Test
public void star_becomes_dot_star() throws Exception {
assertEquals("gl.*b", StringUtils.convertGlobToRegex("gl*b"));
}
@Test
public void escaped_star_is_unchanged() throws Exception {
assertEquals("gl\\*b", StringUtils.convertGlobToRegex("gl\\*b"));
}
@Test
public void question_mark_becomes_dot() throws Exception {
assertEquals("gl.b", StringUtils.convertGlobToRegex("gl?b"));
}
@Test
public void escaped_question_mark_is_unchanged() throws Exception {
assertEquals("gl\\?b", StringUtils.convertGlobToRegex("gl\\?b"));
}
@Test
public void character_classes_dont_need_conversion() throws Exception {
assertEquals("gl[-o]b", StringUtils.convertGlobToRegex("gl[-o]b"));
}
@Test
public void escaped_classes_are_unchanged() throws Exception {
assertEquals("gl\\[-o\\]b", StringUtils.convertGlobToRegex("gl\\[-o\\]b"));
}
@Test
public void negation_in_character_classes() throws Exception {
assertEquals("gl[^a-n!p-z]b", StringUtils.convertGlobToRegex("gl[!a-n!p-z]b"));
}
@Test
public void nested_negation_in_character_classes() throws Exception {
assertEquals("gl[[^a-n]!p-z]b", StringUtils.convertGlobToRegex("gl[[!a-n]!p-z]b"));
}
@Test
public void escape_carat_if_it_is_the_first_char_in_a_character_class() throws Exception {
assertEquals("gl[\\^o]b", StringUtils.convertGlobToRegex("gl[^o]b"));
}
@Test
public void metachars_are_escaped() throws Exception {
assertEquals("gl..*\\.\\(\\)\\+\\|\\^\\$\\@\\%b", StringUtils.convertGlobToRegex("gl?*.()+|^$@%b"));
}
@Test
public void metachars_in_character_classes_dont_need_escaping() throws Exception {
assertEquals("gl[?*.()+|^$@%]b", StringUtils.convertGlobToRegex("gl[?*.()+|^$@%]b"));
}
@Test
public void escaped_backslash_is_unchanged() throws Exception {
assertEquals("gl\\\\b", StringUtils.convertGlobToRegex("gl\\\\b"));
}
@Test
public void slashQ_and_slashE_are_escaped() throws Exception {
assertEquals("\\\\Qglob\\\\E", StringUtils.convertGlobToRegex("\\Qglob\\E"));
}
@Test
public void braces_are_turned_into_groups() throws Exception {
assertEquals("(glob|regex)", StringUtils.convertGlobToRegex("{glob,regex}"));
}
@Test
public void escaped_braces_are_unchanged() throws Exception {
assertEquals("\\{glob\\}", StringUtils.convertGlobToRegex("\\{glob\\}"));
}
@Test
public void commas_dont_need_escaping() throws Exception {
assertEquals("(glob,regex),", StringUtils.convertGlobToRegex("{glob\\,regex},"));
}
}
글로브와 같은 패턴의 매칭을 실시하는 라이브러리는, 다음의 라이브러리보다 최신인 것이 몇개 있습니다.
Theres Ants 디렉토리 스캐너 및 Springs AntPathMatcher
Ant Style Globing은 Java 세계(Hudson, Spring, Ant 및 Maven)에서 거의 표준적인 글로벌 구문이 되었기 때문에 다른 솔루션보다 둘 다 추천합니다.
저는 최근에 해야 돼서\Q
★★★★★★★★★★★★★★★★★」\E
「 」 「 」 턴어 :
private static Pattern getPatternFromGlob(String glob) {
return Pattern.compile(
"^" + Pattern.quote(glob)
.replace("*", "\\E.*\\Q")
.replace("?", "\\E.\\Q")
+ "$");
}
이것은 *와 ?를 패턴으로 처리하는 간단한 Glob 구현입니다.
public class GlobMatch {
private String text;
private String pattern;
public boolean match(String text, String pattern) {
this.text = text;
this.pattern = pattern;
return matchCharacter(0, 0);
}
private boolean matchCharacter(int patternIndex, int textIndex) {
if (patternIndex >= pattern.length()) {
return false;
}
switch(pattern.charAt(patternIndex)) {
case '?':
// Match any character
if (textIndex >= text.length()) {
return false;
}
break;
case '*':
// * at the end of the pattern will match anything
if (patternIndex + 1 >= pattern.length() || textIndex >= text.length()) {
return true;
}
// Probe forward to see if we can get a match
while (textIndex < text.length()) {
if (matchCharacter(patternIndex + 1, textIndex)) {
return true;
}
textIndex++;
}
return false;
default:
if (textIndex >= text.length()) {
return false;
}
String textChar = text.substring(textIndex, textIndex + 1);
String patternChar = pattern.substring(patternIndex, patternIndex + 1);
// Note the match is case insensitive
if (textChar.compareToIgnoreCase(patternChar) != 0) {
return false;
}
}
// End of pattern and text?
if (patternIndex + 1 >= pattern.length() && textIndex + 1 >= text.length()) {
return true;
}
// Go on to match the next character in the pattern
return matchCharacter(patternIndex + 1, textIndex + 1);
}
}
토니 엣지콤의 답변과 유사하게, 여기 짧고 간단한 글로버가 있습니다.*
★★★★★★★★★★★★★★★★★」?
를 사용하지 않고 regex 를 합니다.
public static boolean matches(String text, String glob) {
String rest = null;
int pos = glob.indexOf('*');
if (pos != -1) {
rest = glob.substring(pos + 1);
glob = glob.substring(0, pos);
}
if (glob.length() > text.length())
return false;
// handle the part up to the first *
for (int i = 0; i < glob.length(); i++)
if (glob.charAt(i) != '?'
&& !glob.substring(i, i + 1).equalsIgnoreCase(text.substring(i, i + 1)))
return false;
// recurse for the part after the first *, if any
if (rest == null) {
return glob.length() == text.length();
} else {
for (int i = glob.length(); i <= text.length(); i++) {
if (matches(text.substring(i), rest))
return true;
}
return false;
}
}
을 사용하다NIO2에서 Files.newDirectoryStream(Path dir, String glob)
모든 코드라는 . 모든 매치가 새로워질 수 있도록 주의하세요.Path
오브젝트가 생성됩니다.지금까지는 Windows FS에서만 테스트할 수 있었습니다만, Unix에서도 동작할 수 있다고 생각합니다.
// a file system hack to get a glob matching
PathMatcher matcher = ("*".equals(glob)) ? null
: FileSystems.getDefault().getPathMatcher("glob:" + glob);
if ("*".equals(glob) || matcher.matches(Paths.get(someName))) {
// do you stuff here
}
UPDATE는 Mac과 Linux에서 모두 동작합니다.
「표준」의 실장은 모르지만, BSD 라이센스에 근거해 릴리스 된 파일의 글로벌 매칭을 실장하는 소스 포지의 프로젝트는 알고 있습니다.하나의 파일로 구현되므로 필요에 따라 조정할 수 있습니다.
Vincent Robert/dimo414의 이전 솔루션은Pattern.quote()
관점에서 구현되는 모습\Q
...\E
이는 API에 기재되어 있지 않기 때문에 기타 또는 미래의 Java 구현에는 해당되지 않을 수 있습니다.다음 솔루션에서는 다음과 같은 문제가 발생하지 않도록 함으로써 구현 의존성을 제거합니다.\E
사용하는 대신quote()
또한 활성화 됩니다.DOTALL
모드((?s)
대조하는 문자열에 줄바꿈이 포함되어 있는 경우).
public static Pattern globToRegex(String glob)
{
return Pattern.compile(
"(?s)^\\Q" +
glob.replace("\\E", "\\E\\\\E\\Q")
.replace("*", "\\E.*\\Q")
.replace("?", "\\E.\\Q") +
"\\E$"
);
}
있어sun.nio.fs.Globs
퍼블릭 API의 일부가 아닙니다.다음을 통해 간접적으로 사용할 수 있습니다.
FileSystems.getDefault().getPathMatcher("glob:<myPattern>")
그러나 PathMatcher를 반환하므로 작업이 불편합니다.Path만을 파라미터로 받아들일 수 있기 때문입니다(File은 사용할 수 없습니다).
하나의 가능한 옵션은 PathMatcher를 regex 패턴으로 변환하는 것입니다('toString()' 메서드를 호출하기만 하면 됩니다).
또 다른 옵션은 glob-library-java와 같은 전용 Glob 라이브러리를 사용하는 것입니다.
오래 전에 글로벌 기반의 대규모 텍스트 필터링을 실시했기 때문에 작은 코드(코드 15줄, JDK 이외의 의존관계 없음)를 작성했습니다.'*'만 처리할 수 있지만 '?'는 쉽게 확장할 수 있습니다.이는 사전 컴파일된 regexp보다 몇 배 고속이며 사전 컴파일이 필요하지 않습니다(본질적으로 패턴이 일치할 때마다 string-vs-string 비교입니다).
코드:
public static boolean miniglob(String[] pattern, String line) {
if (pattern.length == 0) return line.isEmpty();
else if (pattern.length == 1) return line.equals(pattern[0]);
else {
if (!line.startsWith(pattern[0])) return false;
int idx = pattern[0].length();
for (int i = 1; i < pattern.length - 1; ++i) {
String patternTok = pattern[i];
int nextIdx = line.indexOf(patternTok, idx);
if (nextIdx < 0) return false;
else idx = nextIdx + patternTok.length();
}
if (!line.endsWith(pattern[pattern.length - 1])) return false;
return true;
}
}
사용방법:
public static void main(String[] args) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
// read from stdin space separated text and pattern
for (String input = in.readLine(); input != null; input = in.readLine()) {
String[] tokens = input.split(" ");
String line = tokens[0];
String[] pattern = tokens[1].split("\\*+", -1 /* want empty trailing token if any */);
// check matcher performance
long tm0 = System.currentTimeMillis();
for (int i = 0; i < 1000000; ++i) {
miniglob(pattern, line);
}
long tm1 = System.currentTimeMillis();
System.out.println("miniglob took " + (tm1-tm0) + " ms");
// check regexp performance
Pattern reptn = Pattern.compile(tokens[1].replace("*", ".*"));
Matcher mtchr = reptn.matcher(line);
tm0 = System.currentTimeMillis();
for (int i = 0; i < 1000000; ++i) {
mtchr.matches();
}
tm1 = System.currentTimeMillis();
System.out.println("regexp took " + (tm1-tm0) + " ms");
// check if miniglob worked correctly
if (miniglob(pattern, line)) {
System.out.println("+ >" + line);
}
else {
System.out.println("- >" + line);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
복사/붙여넣기
그런데 Perl에서는 힘든 방법으로 한 것 같습니다.
Perl에서는 다음과 같이 동작합니다.
my @files = glob("*.html")
# Or, if you prefer:
my @files = <*.html>
언급URL : https://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns
'programing' 카테고리의 다른 글
중첩된 JavaScript 개체를 평탄화/평탄화 해제하는 가장 빠른 방법 (0) | 2022.11.21 |
---|---|
문자열 매개 변수를 정수 열에 암묵적으로 캐스팅하는 MariaDB 10.3 실패 (0) | 2022.11.21 |
"org.mariadb.jdbc"라는 이름의 JBOSS 드라이버.드라이버"가 인스톨 되어 있지 않다. (0) | 2022.11.21 |
mysql은 어디에 데이터를 저장합니까? (0) | 2022.11.21 |
JavaScript/jQuery를 사용한 파일 다운로드 (0) | 2022.11.02 |