여러 줄로 구분 된 여러 줄 문자열이 있습니다.
(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)
이 문자열을을 사용하여 부분으로 나눌 수 String.split있지만 구분 기호 정규 표현식과 일치하는 실제 문자열을 얻을 수없는 것 같습니다.
즉, 이것이 내가 얻는 것입니다.
Text1Text2Text3Text4
이것이 내가 원하는거야
Text1DelimiterAText2DelimiterCText3DelimiterBText4
구분 기호 정규식을 사용하여 문자열을 분할하고 구분 기호를 유지하는 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"
}
}
