source

문자열을 분할하고 구분 기호를 유지하는 방법

goodcode 2022. 7. 31. 23:00
반응형

문자열을 분할하고 구분 기호를 유지하는 방법

여러 개의 딜리미터로 구분된 여러 줄의 문자열이 있습니다.

(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)

수 요.String.split그러나 딜리미터 regex와 일치하는 실제 문자열을 얻을 수 없는 것 같습니다.

즉, 다음과 같은 것을 얻을 수 있는 것은 다음과 같습니다.

  • Text1
  • Text2
  • Text3
  • Text4

이게 내가 원하는 거야

  • Text1
  • DelimiterA
  • Text2
  • DelimiterC
  • Text3
  • DelimiterB
  • Text4

딜리미터 regex를 사용하여 문자열을 분할하고 딜리미터를 유지하는 JDK 방법이 있습니까?

정규식의 기능인 룩어헤드 및 룩백을 사용할 수 있습니다.

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의 코멘트는 유효합니다.정규 표현에서는 가독성이 항상 문제가 됩니다.정규식을 읽기 쉽게 만들기 위해 수행하는 작업 중 하나는 변수를 만드는 것입니다. 변수의 이름은 정규식이 수행하는 작업을 나타냅니다.플레이스 홀더를 배치할 수도 있습니다(예:%1$s를 사용합니다.String.format플레이스 홀더를 사용할 실제 문자열로 바꿉니다.하다

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, ";"));
    ...
}

룩어라운드를 사용하여 제로 폭 일치로 분할하는 경우.다음은 몇 가지 예입니다.

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][!!]"
    }
}

네, 마지막 패턴에서 세 번 강조된 주장입니다.

관련 질문

「 」를 참조해 주세요.

regex를 수반하지 않는 매우 순진한 솔루션은 다음과 같은 행에 따라 딜리미터에 문자열 치환을 실행하는 것입니다(딜리미터는 콤마로 가정).

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 를 참조해 주세요.

세 번째 urgument를 true로 넘기세요.딜리미터도 반환됩니다.

StringTokenizer(String str, String delimiters, true);

매우 오래된 질문이라는 것을 알고 있으며, 답변도 받아들여지고 있습니다.하지만 여전히 나는 원래의 질문에 매우 간단한 답변을 제출하고 싶다.다음 코드를 고려하십시오.

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텍스트 시작일 때를 제외하고 단어를 구분합니다.

제가 늦게 도착했는데, 원래 질문으로 돌아가서, 그냥 룩어라운드를 사용하면 어떨까요?

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]

EDIT: 위에 보이는 것은 해당 코드를 실행하면 명령줄에 표시되는 내용입니다만, 조금 혼란스럽다는 것을 알 수 있습니다.되었는지 알 수Arrays.toString()SO의 구문 강조 표시도 도움이 되지 않습니다.이러한 어레이를 소스코드로 선언한 것은 다음과 같습니다.

{ "'", "ab", "','", "cd", "','", "eg", "'" }
{ "boo", ":", "and", ":", "foo" }

그게 더 읽기 쉬웠으면 좋겠어요.알려줘서 고마워, @finnw.

위의 답변을 봤는데 솔직히 만족스러운 답변이 하나도 없네요.기본적으로 Perl 스플릿 기능을 모방해야 합니다.왜 Java가 이를 허용하지 않고 join() 메서드를 사용하는지 이해할 수 없지만, 저는 이 문제를 언급하고 싶습니다.이런 거 수업도 필요없잖아그냥 함수일 뿐이야.다음 샘플 프로그램을 실행합니다.

이전 답변 중 일부는 과도한 null-checking을 포함하고 있으며, 최근 여기에 질문에 대한 답변을 작성했습니다.

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으로 대체됩니다(구분자는 포함되지 않습니다).

그래서 StringTokenizerEx를 구현했습니다.StringTokenizerEx는 반복 가능하며 문자열을 분할하려면 진정한 regexp가 필요합니다.

는 딜리미터를 형성하기합니다.true regexp는 ' 시퀀스'가 아닙니다.
는 '하고 '는 세 구분 기호로에 두 빈 있습니다: 'o'는 'o'로 구분됩니다.

[o], '', [o], '', [o]

그러나 regexp o+는 "aooob"을 분할할 때 예상된 결과를 반환합니다.

[], 'a', [ooo], 'b', []

이 StringTokenizer를 사용하려면예:

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 스니펫에서 사용할 수 있습니다.

코드 챌린지 응답(테스트 케이스가 포함된 자기포함 클래스 1개)의 경우와 마찬가지로 복사 붙여넣기('src/test' 디렉토리)를 실행합니다.main() 메서드는 다양한 사용법을 보여줍니다.


주의: (2009년 후반 편집)

기사 Final Thoughts: Java Puzzler: Spliting Hairs는 의 기괴한 행동을 설명하는 좋은 일을 한다.String.split().
조쉬 블로흐

아, 아, 아, 아, 아, 아, 아, 아, 아.FWIW Perl f fw 。
Mike "madbot" McCloskey 。Mike는 Java의 정규식이 거의 모든 30K Perl 정규식 테스트를 통과하고 더 빠르게 실행되었음을 확인했습니다.

Google 공통 라이브러리 Guava에는 다음과 같은 스플리터도 포함되어 있습니다.

  • 사용하기 쉽다
  • Google(고객이 아닌)에 의해 유지보수됩니다.

그래서 확인해 볼 가치가 있을 것이다.초기 개략 문서(pdf):

JDK의 특징은 다음과 같습니다.

String[] pieces = "foo.bar".split("\\.");

원하는 대로 사용할 수 있습니다. - 정규 표현 - 결과 배열 - 빈 조각을 처리하는 방법

Mini-puzler: ",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.on(',').split(" foo, ,bar, quux,")
--> [" foo", " ", "bar", " quux", ""]

추가 기능을 원하시면 요청하세요!

Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split(" foo, ,bar, quux,")
--> ["foo", "bar", "quux"]

구성 메서드의 순서는 중요하지 않습니다. 분할하는 동안 트리밍은 빈 공간을 확인하기 전에 수행됩니다.

여기에서는, 다음과 같은 심플한 클린 실장을 실시합니다.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]);
}

.Pattern#split가가왜 왜? ???에 i i가 에 들지 않는다if이지만 일관성을 하기 위해 합니다.Pattern#split그렇지 않으면 무조건 추가되므로 입력 문자열이 패턴으로 끝나는 경우 결과의 마지막 요소로 빈 문자열이 됩니다.

String [ ]로 변환하여 String [ ]와의합니다.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()]);
}

regex를 사용하는 다른 후보 솔루션.토큰 순서를 유지하고 동일한 유형의 여러 토큰을 한 행에 올바르게 일치시킵니다.단점은 정규식이 좀 심하다는 것이다.

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]);
}

Pattern과 Matcher를 사용하는 것이 좋습니다.이것은 거의 확실히 당신이 원하는 것을 달성할 수 있습니다.정규 표현은 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");

중요사항:이 기능은 String에 더 이상의 "새로운 구분자"가 없는 경우에만 작동합니다.따라서 일반적인 해결책은 아닙니다.단, Char Sequence가 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|'|

조금 과한... :-)

일치하는 패턴을 목록에 포함하도록 조정된 패턴.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)
}

그럼에도 불구하고 매우 순진하고 비효율적인 해결책입니다.문자열에서 두 번 분할을 사용한 후 두 개의 어레이를 연결합니다.

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));

이 질문의 하위 항목 중 하나는 "선행 구분 기호" 질문과 관련이 있습니다. 토큰과 구분 기호 중 어느 것으로 시작할지 알아야 합니다.물론 선행 구분선을 폐기해야 한다고 가정할 수 있지만 이는 부당한 가정으로 보입니다.후행 구분 기호가 있는지 여부도 확인할 수 있습니다.이에 따라 2개의 부울 플래그가 설정됩니다.

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" )

            }

는, 스플릿 해 주세요.이 있습니다..split()★★★★★★ 。

다음의 예를 참조해 주세요.

public class SplitExample {


    public static void main(String[] args) {  
        String str = "Javathomettt";  
        System.out.println("method 1");
        System.out.println("Returning words:");  
        String[] arr = str.split("t", 40);  
        for (String w : arr) {  
            System.out.println(w+"t");  
        }  
        System.out.println("Split array length: "+arr.length);  
        System.out.println("method 2");
        System.out.println(str.replaceAll("t", "\n"+"t"));
    }

자바에 대해서는 잘 모르지만, 만약 그것을 할 수 있는 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

반응형