문자열을 나누는 방법과 구분 기호를 유지하는 방법은 무엇입니까?
여러 줄로 구분 된 여러 줄 문자열이 있습니다.
(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"
}
}
StringTokenizer라는 아이디어는 Enumerable이기 때문에 좋아합니다.
그러나 그것은 또한 더 이상 사용되지 않으며, 지루한 String []을 반환하는 String.split으로 대체됩니다 (구분자를 포함하지 않습니다).
그래서 Iterable 인 StringTokenizerEx를 구현했으며 문자열을 분할하는 데 실제 정규 표현식이 필요합니다.
진정한 정규 표현식은 구분 기호를 형성하기 위해 반복되는 '문자 시퀀스'가 아님을 의미합니다.
'o'는 'o'와만 일치하고 'ooo'는 두 개의 빈 문자열이있는 세 개의 구분 기호로 분할됩니다.
[o], '', [o], '', [o]
그러나 정규 표현식 o +는 "aooob"를 분할 할 때 예상 결과를 반환합니다
[], 'a', [ooo], 'b', []
이 StringTokenizerEx를 사용하려면
final StringTokenizerEx aStringTokenizerEx = new StringTokenizerEx("boo:and:foo", "o+");
final String firstDelimiter = aStringTokenizerEx.getDelimiter();
for(String aString: aStringTokenizerEx )
{
// uses the split String detected and memorized in 'aString'
final nextDelimiter = aStringTokenizerEx.getDelimiter();
}
이 클래스의 코드는 DZone Snippets 에서 사용할 수 있습니다 .
코드 챌린지 응답 (테스트 케이스가 포함 된 하나의 자체 포함 클래스)에 대해 평소와 같이 복사하여 ( 'src / test'디렉토리에) 붙여 넣기 를 실행하십시오 . main () 메소드는 다양한 사용법을 보여줍니다.
참고 : (2009 년 말 편집)
Final Thoughts : Java Puzzler : Splitting Hairs 기사 는 기괴한 동작을 설명하는 좋은 작업을 수행합니다 String.split()
.
조쉬 블로흐 (Josh Bloch)도이 기사에 대한 답변으로 다음과 같이 논평했다
예, 이것은 고통입니다. FWIW는 Perl과의 호환성이라는 아주 좋은 이유로 이루어졌습니다.
그것을 한 사람은 Mike "madbot"McCloskey이며, 현재 Google에서 우리와 함께 일합니다. Mike는 Java의 정규 표현식이 30K Perl 정규 표현식 테스트를 거의 모두 통과하고 더 빠르게 실행되도록했습니다.
Google 공통 라이브러리 Guava 에는 다음과 같은 스플리터도 포함되어 있습니다.
- 사용하기 더 간단
- Google이 관리하며 귀하가 아닌
따라서 체크 아웃 할 가치가 있습니다. 자신의에서 초기 거친 문서 (PDF) :
JDK에는 다음이 있습니다.
String[] pieces = "foo.bar".split("\\.");
정확히 무엇을 원한다면 이것을 사용하는 것이 좋습니다 :-정규 표현식-배열 결과-빈 조각을 처리하는 방법
미니 퍼즐 : ", a ,, b,". split ( ",") 반환 ...
(a) "", "a", "", "b", ""
(b) null, "a", null, "b", null
(c) "a", null, "b"
(d) "a", "b"
(e) None of the above
답 : (e) 위의 어느 것도 아닙니다.
",a,,b,".split(",")
returns
"", "a", "", "b"
후행 빈 용기 만 건너 뜁니다! (누구를 피할 수있는 해결 방법을 알고있는 사람은 누구입니까?)
어쨌든 Splitter는 더 유연합니다. 기본 동작은 단순합니다.
Splitter.on(',').split(" foo, ,bar, quux,")
--> [" foo", " ", "bar", " quux", ""]
추가 기능을 원하면 요청하십시오!
Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split(" foo, ,bar, quux,")
--> ["foo", "bar", "quux"]
구성 방법의 순서는 중요하지 않습니다. 분리하는 동안 빈을 확인하기 전에 트리밍이 발생합니다.
3 번째 aurgument를 "true"로 전달하십시오. 분리 문자도 리턴합니다.
StringTokenizer(String str, String delimiters, true);
다음은 Pattern#split
지원되지 않는 가변 길이 패턴과 일관 되고 작동 하는 간단한 깔끔한 구현입니다 . 사용이 더 쉽습니다. @cletus에서 제공 하는 솔루션 과 유사합니다 .
public static String[] split(CharSequence input, String pattern) {
return split(input, Pattern.compile(pattern));
}
public static String[] split(CharSequence input, Pattern pattern) {
Matcher matcher = pattern.matcher(input);
int start = 0;
List<String> result = new ArrayList<>();
while (matcher.find()) {
result.add(input.subSequence(start, matcher.start()).toString());
result.add(matcher.group());
start = matcher.end();
}
if (start != input.length()) result.add(input.subSequence(start, input.length()).toString());
return result.toArray(new String[0]);
}
나는 여기서 null 점검을 Pattern#split
하지 않고, 왜, 왜해야합니까. 끝에을 좋아하지 않지만 . if
와 일관성이 필요합니다 Pattern#split
. 그렇지 않으면 입력 문자열이 패턴으로 끝나는 경우 무조건 추가하여 결과의 마지막 요소로 빈 문자열을 만듭니다.
나는 []와 일관성을 문자열로 변환 Pattern#split
, 내가 사용하는 new String[0]
것이 아니라 new String[result.size()]
, 참조 여기에 이유에 대해.
내 테스트는 다음과 같습니다.
@Test
public void splitsVariableLengthPattern() {
String[] result = Split.split("/foo/$bar/bas", "\\$\\w+");
Assert.assertArrayEquals(new String[] { "/foo/", "$bar", "/bas" }, result);
}
@Test
public void splitsEndingWithPattern() {
String[] result = Split.split("/foo/$bar", "\\$\\w+");
Assert.assertArrayEquals(new String[] { "/foo/", "$bar" }, result);
}
@Test
public void splitsStartingWithPattern() {
String[] result = Split.split("$foo/bar", "\\$\\w+");
Assert.assertArrayEquals(new String[] { "", "$foo", "/bar" }, result);
}
@Test
public void splitsNoMatchesPattern() {
String[] result = Split.split("/foo/bar", "\\$\\w+");
Assert.assertArrayEquals(new String[] { "/foo/bar" }, result);
}
작업 버전도 게시합니다 (먼저 Markus와 유사 함).
public static String[] splitIncludeDelimeter(String regex, String text){
List<String> list = new LinkedList<>();
Matcher matcher = Pattern.compile(regex).matcher(text);
int now, old = 0;
while(matcher.find()){
now = matcher.end();
list.add(text.substring(old, now));
old = now;
}
if(list.size() == 0)
return new String[]{text};
//adding rest of a text as last element
String finalElement = text.substring(old);
list.add(finalElement);
return list.toArray(new String[list.size()]);
}
그리고 여기에 두 번째 솔루션이 있으며 첫 번째 솔루션보다 50 % 더 빠릅니다.
public static String[] splitIncludeDelimeter2(String regex, String text){
List<String> list = new LinkedList<>();
Matcher matcher = Pattern.compile(regex).matcher(text);
StringBuffer stringBuffer = new StringBuffer();
while(matcher.find()){
matcher.appendReplacement(stringBuffer, matcher.group());
list.add(stringBuffer.toString());
stringBuffer.setLength(0); //clear buffer
}
matcher.appendTail(stringBuffer); ///dodajemy reszte ciagu
list.add(stringBuffer.toString());
return list.toArray(new String[list.size()]);
}
정규식을 사용하는 또 다른 후보 솔루션. 토큰 순서를 유지하고 같은 유형의 여러 토큰을 연속으로 정확하게 일치시킵니다. 단점은 정규 표현식이 불쾌하다는 것입니다.
package javaapplication2;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JavaApplication2 {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String num = "58.5+variable-+98*78/96+a/78.7-3443*12-3";
// Terrifying regex:
// (a)|(b)|(c) match a or b or c
// where
// (a) is one or more digits optionally followed by a decimal point
// followed by one or more digits: (\d+(\.\d+)?)
// (b) is one of the set + * / - occurring once: ([+*/-])
// (c) is a sequence of one or more lowercase latin letter: ([a-z]+)
Pattern tokenPattern = Pattern.compile("(\\d+(\\.\\d+)?)|([+*/-])|([a-z]+)");
Matcher tokenMatcher = tokenPattern.matcher(num);
List<String> tokens = new ArrayList<>();
while (!tokenMatcher.hitEnd()) {
if (tokenMatcher.find()) {
tokens.add(tokenMatcher.group());
} else {
// report error
break;
}
}
System.out.println(tokens);
}
}
샘플 출력 :
[58.5, +, variable, -, +, 98, *, 78, /, 96, +, a, /, 78.7, -, 3443, *, 12, -, 3]
Java API 에서이 기능을 수행하는 기존 함수를 알지 못하지만 (존재하지 않음) 여기에는 자체 구현이 있습니다 (하나 이상의 구분 기호가 단일 토큰으로 반환됩니다. 원하는 경우 각 구분 기호는 별도의 토큰으로 반환되므로 약간의 적응이 필요합니다.
static String[] splitWithDelimiters(String s) {
if (s == null || s.length() == 0) {
return new String[0];
}
LinkedList<String> result = new LinkedList<String>();
StringBuilder sb = null;
boolean wasLetterOrDigit = !Character.isLetterOrDigit(s.charAt(0));
for (char c : s.toCharArray()) {
if (Character.isLetterOrDigit(c) ^ wasLetterOrDigit) {
if (sb != null) {
result.add(sb.toString());
}
sb = new StringBuilder();
wasLetterOrDigit = !wasLetterOrDigit;
}
sb.append(c);
}
result.add(sb.toString());
return result.toArray(new String[0]);
}
필자는 원하는 것을 거의 확실하게 달성 할 패턴과 매처를 사용하는 것이 좋습니다. 정규식은 String.split에서 사용하는 것보다 다소 복잡해야합니다.
나는 그것이 가능하다고 생각하지 않지만 String#split
, 당신은 StringTokenizer
구분 기호를 정규식으로 정의 할 수는 없지만 한 자리 문자의 클래스로만 정의 할 수는 있지만를 사용할 수는 있습니다 :
new StringTokenizer("Hello, world. Hi!", ",.!", true); // true for returnDelims
여유가 있다면 Java의 replace (CharSequence target, CharSequence replacement) 방법을 사용하고 분리 할 다른 구분자를 채우십시오. 예 : 문자열 "boo : and : foo"를 분할하고 오른쪽 문자열에 ':'을 유지하고 싶습니다.
String str = "boo:and:foo";
str = str.replace(":","newdelimiter:");
String[] tokens = str.split("newdelimiter");
중요 사항 : 이것은 문자열에 "newdelimiter"가 더 이상없는 경우에만 작동합니다! 따라서 일반적인 솔루션이 아닙니다. 그러나 CharSequence를 알고 있으면 String에 나타나지 않을 것입니다. 이것은 매우 간단한 해결책입니다.
빠른 답변 : \ b와 같은 비 물리적 경계를 사용하여 분할하십시오. 나는 그것이 작동하는지 (PHP와 JS에서 사용되는지) 시험하려고 노력할 것이다.
가능하고 일종의 작업이지만 너무 많이 분리 될 수 있습니다. 실제로 분할하려는 문자열과 필요한 결과에 따라 다릅니다. 자세한 내용을 알려 주시면 더 나은 도움을 드리겠습니다.
다른 방법은 구분 기호를 캡처하고 (변수로 가정) 나중에 결과에 추가하여 자신의 분할을 수행하는 것입니다.
나의 빠른 테스트 :
String str = "'ab','cd','eg'";
String[] stra = str.split("\\b");
for (String s : stra) System.out.print(s + "|");
System.out.println();
결과:
'|ab|','|cd|','|eg|'|
조금 너무 ... :-)
불통 Pattern.split ()는 리스트에 매칭 패턴을 포함하는
추가
// add match to the list
matchList.add(input.subSequence(start, end).toString());
전체 소스
public static String[] inclusiveSplit(String input, String re, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<String>();
Pattern pattern = Pattern.compile(re);
Matcher m = pattern.matcher(input);
// Add segments before each match found
while (m.find()) {
int end = m.end();
if (!matchLimited || matchList.size() < limit - 1) {
int start = m.start();
String match = input.subSequence(index, start).toString();
matchList.add(match);
// add match to the list
matchList.add(input.subSequence(start, end).toString());
index = end;
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index, input.length())
.toString();
matchList.add(match);
index = end;
}
}
// If no match was found, return this
if (index == 0)
return new String[] { input.toString() };
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize - 1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
위의 코드 중 일부를 기반으로하는 그루비 버전이 있습니다. 어쨌든 짧습니다. 머리와 꼬리를 조건부로 포함합니다 (비어 있지 않은 경우). 마지막 부분은 데모 / 테스트 사례입니다.
List splitWithTokens(str, pat) {
def tokens=[]
def lastMatch=0
def m = str=~pat
while (m.find()) {
if (m.start() > 0) tokens << str[lastMatch..<m.start()]
tokens << m.group()
lastMatch=m.end()
}
if (lastMatch < str.length()) tokens << str[lastMatch..<str.length()]
tokens
}
[['<html><head><title>this is the title</title></head>',/<[^>]+>/],
['before<html><head><title>this is the title</title></head>after',/<[^>]+>/]
].each {
println splitWithTokens(*it)
}
그럼에도 불구하고 작동하는 매우 순진하고 비효율적 인 솔루션 문자열에서 split을 두 번 사용한 다음 두 배열을 연결
String temp[]=str.split("\\W");
String temp2[]=str.split("\\w||\\s");
int i=0;
for(String string:temp)
System.out.println(string);
String temp3[]=new String[temp.length-1];
for(String string:temp2)
{
System.out.println(string);
if((string.equals("")!=true)&&(string.equals("\\s")!=true))
{
temp3[i]=string;
i++;
}
// System.out.println(temp.length);
// System.out.println(temp2.length);
}
System.out.println(temp3.length);
String[] temp4=new String[temp.length+temp3.length];
int j=0;
for(i=0;i<temp.length;i++)
{
temp4[j]=temp[i];
j=j+2;
}
j=1;
for(i=0;i<temp3.length;i++)
{
temp4[j]=temp3[i];
j+=2;
}
for(String s:temp4)
System.out.println(s);
String expression = "((A+B)*C-D)*E";
expression = expression.replaceAll("\\+", "~+~");
expression = expression.replaceAll("\\*", "~*~");
expression = expression.replaceAll("-", "~-~");
expression = expression.replaceAll("/+", "~/~");
expression = expression.replaceAll("\\(", "~(~"); //also you can use [(] instead of \\(
expression = expression.replaceAll("\\)", "~)~"); //also you can use [)] instead of \\)
expression = expression.replaceAll("~~", "~");
if(expression.startsWith("~")) {
expression = expression.substring(1);
}
String[] expressionArray = expression.split("~");
System.out.println(Arrays.toString(expressionArray));
이 질문의 미묘한 점 중 하나는 "선행 구분 기호"질문과 관련이 있습니다. 토큰과 구분 기호가 결합 된 경우 토큰으로 시작하는지 구분 기호로 시작해야하는지 알아야합니다. 물론 선행 탈회를 버려야한다고 가정 할 수 있지만 이것은 정당하지 않은 가정으로 보입니다. 당신은 또한 후행 delim 여부를 알고 싶을 수도 있습니다. 이에 따라 두 개의 부울 플래그가 설정됩니다.
Groovy로 작성되었지만 Java 버전은 상당히 분명해야합니다.
String tokenRegex = /[\p{L}\p{N}]+/ // a String in Groovy, Unicode alphanumeric
def finder = phraseForTokenising =~ tokenRegex
// NB in Groovy the variable 'finder' is then of class java.util.regex.Matcher
def finderIt = finder.iterator() // extra method added to Matcher by Groovy magic
int start = 0
boolean leadingDelim, trailingDelim
def combinedTokensAndDelims = [] // create an array in Groovy
while( finderIt.hasNext() )
{
def token = finderIt.next()
int finderStart = finder.start()
String delim = phraseForTokenising[ start .. finderStart - 1 ]
// Groovy: above gets slice of String/array
if( start == 0 ) leadingDelim = finderStart != 0
if( start > 0 || leadingDelim ) combinedTokensAndDelims << delim
combinedTokensAndDelims << token // add element to end of array
start = finder.end()
}
// start == 0 indicates no tokens found
if( start > 0 ) {
// finish by seeing whether there is a trailing delim
trailingDelim = start < phraseForTokenising.length()
if( trailingDelim ) combinedTokensAndDelims << phraseForTokenising[ start .. -1 ]
println( "leading delim? $leadingDelim, trailing delim? $trailingDelim, combined array:\n $combinedTokensAndDelims" )
}
Java를 잘 모르지만, 그렇게하는 Split 메소드를 찾을 수 없다면 직접 작성하는 것이 좋습니다.
string[] mySplit(string s,string delimiter)
{
string[] result = s.Split(delimiter);
for(int i=0;i<result.Length-1;i++)
{
result[i] += delimiter; //this one would add the delimiter to each items end except the last item,
//you can modify it however you want
}
}
string[] res = mySplit(myString,myDelimiter);
너무 우아하지는 않지만 그렇게 할 것입니다.
참고 URL : https://stackoverflow.com/questions/2206378/how-to-split-a-string-but-also-keep-the-delimiters
'IT' 카테고리의 다른 글
Bash에서 굵은 텍스트를 어떻게 출력합니까? (0) | 2020.04.25 |
---|---|
iOS 7.0 및 시스템 성능 저하에서 유효하지 않은 컨텍스트 0x0 (0) | 2020.04.25 |
QuotaExceededError : Dom exception 22 : 할당량을 초과 한 스토리지에 무언가를 추가하려고했습니다. (0) | 2020.04.25 |
StringBuilder에 개행을 추가하는 방법 (0) | 2020.04.25 |
CSS3 회전 애니메이션 (0) | 2020.04.25 |