여러 줄로 구분 된 여러 줄 문자열이 있습니다.
(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)
이 문자열을을 사용하여 부분으로 나눌 수 String.split
있지만 구분 기호 정규 표현식과 일치하는 실제 문자열을 얻을 수없는 것 같습니다.
즉, 이것이 내가 얻는 것입니다.
Text1
Text2
Text3
Text4
이것이 내가 원하는거야
Text1
DelimiterA
Text2
DelimiterC
Text3
DelimiterB
Text4
구분 기호 정규식을 사용하여 문자열을 분할하고 구분 기호를 유지하는 JDK 방법이 있습니까?
답변
Lookahead 및 Lookbehind를 사용할 수 있습니다. 이처럼 :
System.out.println(Arrays.toString("a;b;c;d".split("(?<=;)")));
System.out.println(Arrays.toString("a;b;c;d".split("(?=;)")));
System.out.println(Arrays.toString("a;b;c;d".split("((?<=;)|(?=;))")));
그리고 당신은 얻을 것이다 :
[a;, b;, c;, d]
[a, ;b, ;c, ;d]
[a, ;, b, ;, c, ;, d]
마지막은 당신이 원하는 것입니다.
((?<=;)|(?=;))
전 ;
또는 후에 빈 문자를 선택하는 것과 같습니다 ;
.
도움이 되었기를 바랍니다.
가독성에 대한 Fabian Steeg 의견 편집 이 유효합니다. 가독성은 항상 RegEx의 문제입니다. 한 가지, 나는 이것을 완화시키는 데 도움을주기 위해 정규 표현식이하는 것을 나타내는 이름을 가진 변수를 만들고 Java String 형식을 사용하여 도움을줍니다. 이처럼 :
static public final String WITH_DELIMITER = "((?<=%1$s)|(?=%1$s))";
...
public void someMethod() {
...
final String[] aEach = "a;b;c;d".split(String.format(WITH_DELIMITER, ";"));
...
}
...
이것은 약간 도움이됩니다. :-디
답변
둘러보기를 사용하고 너비가 0 인 일치로 분할하려고합니다. 여기 몇 가지 예가 있어요.
public class SplitNDump {
static void dump(String[] arr) {
for (String s : arr) {
System.out.format("[%s]", s);
}
System.out.println();
}
public static void main(String[] args) {
dump("1,234,567,890".split(","));
// "[1][234][567][890]"
dump("1,234,567,890".split("(?=,)"));
// "[1][,234][,567][,890]"
dump("1,234,567,890".split("(?<=,)"));
// "[1,][234,][567,][890]"
dump("1,234,567,890".split("(?<=,)|(?=,)"));
// "[1][,][234][,][567][,][890]"
dump(":a:bb::c:".split("(?=:)|(?<=:)"));
// "[][:][a][:][bb][:][:][c][:]"
dump(":a:bb::c:".split("(?=(?!^):)|(?<=:)"));
// "[:][a][:][bb][:][:][c][:]"
dump(":::a::::b b::c:".split("(?=(?!^):)(?<!:)|(?!:)(?<=:)"));
// "[:::][a][::::][b b][::][c][:]"
dump("a,bb:::c d..e".split("(?!^)\\b"));
// "[a][,][bb][:::][c][ ][d][..][e]"
dump("ArrayIndexOutOfBoundsException".split("(?<=[a-z])(?=[A-Z])"));
// "[Array][Index][Out][Of][Bounds][Exception]"
dump("1234567890".split("(?<=\\G.{4})"));
// "[1234][5678][90]"
// Split at the end of each run of letter
dump("Boooyaaaah! Yippieeee!!".split("(?<=(?=(.)\\1(?!\\1))..)"));
// "[Booo][yaaaa][h! Yipp][ieeee][!!]"
}
}
그리고 그렇습니다, 그것은 마지막 패턴에서 삼중으로 주장 된 주장입니다.
관련 질문
- Java split이 내 캐릭터를 먹고 있습니다.
- 문자열 분할에서 너비가 0 인 정규 표현식을 사용할 수 있습니까?
- Java에서 CamelCase를 사람이 읽을 수있는 이름으로 어떻게 변환합니까?
- lookbehind의 역 참조
또한보십시오
답변
정규 표현식과 관련이없는 매우 순진한 해결책은 구분 기호에 쉼표를 가정하여 구분 기호에 문자열 대체를 수행하는 것입니다.
string.replace(FullString, "," , "~,~")
tilda (~)를 고유 한 구분 기호로 바꿀 수있는 곳.
그런 다음 새 구분 기호를 나누면 원하는 결과를 얻을 수 있다고 생각합니다.
답변
import java.util.regex.*;
import java.util.LinkedList;
public class Splitter {
private static final Pattern DEFAULT_PATTERN = Pattern.compile("\\s+");
private Pattern pattern;
private boolean keep_delimiters;
public Splitter(Pattern pattern, boolean keep_delimiters) {
this.pattern = pattern;
this.keep_delimiters = keep_delimiters;
}
public Splitter(String pattern, boolean keep_delimiters) {
this(Pattern.compile(pattern==null?"":pattern), keep_delimiters);
}
public Splitter(Pattern pattern) { this(pattern, true); }
public Splitter(String pattern) { this(pattern, true); }
public Splitter(boolean keep_delimiters) { this(DEFAULT_PATTERN, keep_delimiters); }
public Splitter() { this(DEFAULT_PATTERN); }
public String[] split(String text) {
if (text == null) {
text = "";
}
int last_match = 0;
LinkedList<String> splitted = new LinkedList<String>();
Matcher m = this.pattern.matcher(text);
while (m.find()) {
splitted.add(text.substring(last_match,m.start()));
if (this.keep_delimiters) {
splitted.add(m.group());
}
last_match = m.end();
}
splitted.add(text.substring(last_match));
return splitted.toArray(new String[splitted.size()]);
}
public static void main(String[] argv) {
if (argv.length != 2) {
System.err.println("Syntax: java Splitter <pattern> <text>");
return;
}
Pattern pattern = null;
try {
pattern = Pattern.compile(argv[0]);
}
catch (PatternSyntaxException e) {
System.err.println(e);
return;
}
Splitter splitter = new Splitter(pattern);
String text = argv[1];
int counter = 1;
for (String part : splitter.split(text)) {
System.out.printf("Part %d: \"%s\"\n", counter++, part);
}
}
}
/*
Example:
> java Splitter "\W+" "Hello World!"
Part 1: "Hello"
Part 2: " "
Part 3: "World"
Part 4: "!"
Part 5: ""
*/
나는 앞뒤로 빈 요소를 얻는 다른 방법을 좋아하지 않습니다. 분리 문자는 일반적으로 문자열의 시작 또는 끝에 있지 않으므로 두 개의 양호한 배열 슬롯을 낭비하게됩니다.
편집 : 고정 된 경우. 테스트 사례가있는 주석 처리 된 소스는 다음에서 찾을 수 있습니다. http://snippets.dzone.com/posts/show/6453
답변
늦게 도착했지만 원래 질문으로 돌아가서 둘러보기를 사용하지 않는 이유는 무엇입니까?
Pattern p = Pattern.compile("(?<=\\w)(?=\\W)|(?<=\\W)(?=\\w)");
System.out.println(Arrays.toString(p.split("'ab','cd','eg'")));
System.out.println(Arrays.toString(p.split("boo:and:foo")));
산출:
[', ab, ',', cd, ',', eg, ']
[boo, :, and, :, foo]
편집 : 위의 내용은 해당 코드를 실행할 때 명령 줄에 나타나는 내용이지만 약간 혼란 스럽습니다. 어떤 쉼표가 결과의 일부이고 어떤 쉼표가 추가되었는지 추적하기는 어렵습니다 Arrays.toString()
. SO의 구문 강조는 도움이되지 않습니다. 강조 표시 가 저를 대신하지 않고 나와 함께 작동하도록하기 위해 소스 코드에서 이러한 배열을 어떻게 선언했는지 보여줍니다.
{ "'", "ab", "','", "cd", "','", "eg", "'" }
{ "boo", ":", "and", ":", "foo" }
나는 그것이 더 읽기 쉽기를 바랍니다. @finnw 감사합니다.
답변
나는 이것이 매우 오래된 질문이라는 것을 알고 있으며 대답도 받아 들여졌습니다. 그러나 여전히 원래 질문에 대한 간단한 답변을 제출하고 싶습니다. 이 코드를 고려하십시오.
String str = "Hello-World:How\nAre You&doing";
inputs = str.split("(?!^)\\b");
for (int i=0; i<inputs.length; i++) {
System.out.println("a[" + i + "] = \"" + inputs[i] + '"');
}
산출:
a[0] = "Hello"
a[1] = "-"
a[2] = "World"
a[3] = ":"
a[4] = "How"
a[5] = "
"
a[6] = "Are"
a[7] = " "
a[8] = "You"
a[9] = "&"
a[10] = "doing"
텍스트의 시작 부분을 제외하고 단어 경계 \b
를 사용하여 단어를 구분합니다 .
답변
나는 위의 답변을 보았고 정직하게도 만족스럽지 않습니다. 당신이하고 싶은 것은 본질적으로 Perl split 기능을 모방하는 것입니다. 왜 Java가 이것을 허용하지 않고 어딘가에 join () 메소드를 가지고 있습니까? 당신은 이것을 위해 실제로 수업이 필요하지 않습니다. 그저 기능 일뿐입니다. 이 샘플 프로그램을 실행하십시오.
이전 답변 중 일부는 과도한 null 검사가있어 최근에 질문에 대한 답변을 썼습니다.
https://stackoverflow.com/users/18393/cletus
어쨌든 코드 :
public class Split {
public static List<String> split(String s, String pattern) {
assert s != null;
assert pattern != null;
return split(s, Pattern.compile(pattern));
}
public static List<String> split(String s, Pattern pattern) {
assert s != null;
assert pattern != null;
Matcher m = pattern.matcher(s);
List<String> ret = new ArrayList<String>();
int start = 0;
while (m.find()) {
ret.add(s.substring(start, m.start()));
ret.add(m.group());
start = m.end();
}
ret.add(start >= s.length() ? "" : s.substring(start));
return ret;
}
private static void testSplit(String s, String pattern) {
System.out.printf("Splitting '%s' with pattern '%s'%n", s, pattern);
List<String> tokens = split(s, pattern);
System.out.printf("Found %d matches%n", tokens.size());
int i = 0;
for (String token : tokens) {
System.out.printf(" %d/%d: '%s'%n", ++i, tokens.size(), token);
}
System.out.println();
}
public static void main(String args[]) {
testSplit("abcdefghij", "z"); // "abcdefghij"
testSplit("abcdefghij", "f"); // "abcde", "f", "ghi"
testSplit("abcdefghij", "j"); // "abcdefghi", "j", ""
testSplit("abcdefghij", "a"); // "", "a", "bcdefghij"
testSplit("abcdefghij", "[bdfh]"); // "a", "b", "c", "d", "e", "f", "g", "h", "ij"
}
}