কিভাবে একটি স্ট্রিং বিভক্ত, কিন্তু সীমানা রাখা?


243

আমার কাছে একটি মাল্টলাইন স্ট্রিং রয়েছে যা বিভিন্ন সীমানাঙ্কের একটি সেট দ্বারা সীমিত করা হয়:

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

আমি এই স্ট্রিংটি ব্যবহার করে এর অংশগুলিতে বিভক্ত করতে পারি String.split, তবে মনে হয় প্রকৃত স্ট্রিংটি আমি পাই না, যা ডিলিমিটার রেজেক্সের সাথে মিলে।

অন্য কথায়, এটি আমি পাই:

  • Text1
  • Text2
  • Text3
  • Text4

এটাই আমি চাই

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

ডিলিমিটার রেজেক্স ব্যবহার করে স্ট্রিমকে বিভক্ত করার পাশাপাশি ডিলিমেটারগুলি রাখার কোনও জেডিকে উপায় নেই?


এটি ভাবতে আসুন, আপনি সীমান্তকারীদের কোথায় রাখতে চান? শব্দের পাশাপাশি নাকি আলাদা? প্রথম ক্ষেত্রে, আপনি কি তাদের পূর্ববর্তী বা নিম্নলিখিত শব্দের সাথে সংযুক্ত করবেন? দ্বিতীয় ক্ষেত্রে, আমার উত্তরটি আপনার যা প্রয়োজন ...
ফিলিহো

সবেমাত্র একটি ক্লাস প্রয়োগ করেছেন যা আপনাকে যা খুঁজছে তা অর্জনে সহায়তা করবে help নীচে দেখুন
ভনসি

উত্তর:


366

আপনি লুকাহেড এবং লুকবিহ্যান্ড ব্যবহার করতে পারেন। এটার মত:

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]

শেষটি যা আপনি চান তা।

((?<=;)|(?=;))এর আগে ;বা পরে একটি খালি অক্ষর নির্বাচন করতে সমান ;

আশাকরি এটা সাহায্য করবে.

সম্পাদনা পঠনযোগ্যতার উপর দীর্ঘসূত্রী Steeg মন্তব্য বৈধ। পঠনযোগ্যতা সর্বদা RegEx এর সমস্যা। একটি জিনিস, আমি এটিকে সহজ করতে সাহায্য করার জন্য একটি ভেরিয়েবল তৈরি করা যার নাম প্রতিনিধিত্ব করে রেজেক্স কী করে এবং জাভা স্ট্রিং ফর্ম্যাটটি এটি সহায়তা করার জন্য ব্যবহার করে। এটার মত:

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

এটি কিছুটা সাহায্য করে। :-D


2
খুব সুন্দর! এখানে আমরা আবার নিয়মিত প্রকাশের শক্তি দেখতে পারি !!
জর্জ

1
স্ট্রিং # বিভক্তের সাথে এটি করার একটি উপায় আছে তা দেখতে খুব ভাল লাগছে, যদিও আমি চাই যে স্ট্রিংটোকেনাইজারের জন্য যেমন ছিল তেমন সীমানারও অন্তর্ভুক্ত করার উপায় ছিল - এর split(";", true)চেয়ে অনেক বেশি পঠনযোগ্য split("((?<=;)|(?=;))")
ফ্যাবিয়ান স্টেগ

3
এটি হওয়া উচিত: String.format(WITH_DELIMITER, ";");হিসাবে ফর্ম্যাট একটি স্থির পদ্ধতি method
john16384

8
আমি কেবল একটি জটিলতার মুখোমুখি হ'ল ভেরিয়েবল-দৈর্ঘ্যের ডিলিমিটারগুলি (বলুন [\\s,]+) যে আপনি সম্পূর্ণরূপে মিলতে চান। মাঝখানে তাদের সাথে মিল না দেওয়ার জন্য আপনার অতিরিক্ত নেতিবাচক চেহারা প্রয়োজন - যেমন প্রয়োজনীয় রেজেক্সগুলি আরও দীর্ঘ হয়। (?<=[\\s,]+)(?![\\s,])|(?<![\\s,])(?=[\\s,]+)
মিশা পলিটোভস্কি

3
আমি যদি দুটি সীমানা বিভাজক করতে চাই? চল বলি ';' বা ''
অলৌকিক দোহ

78

আপনি চেহারাটি ব্যবহার করতে চান এবং শূন্য-প্রস্থের ম্যাচগুলিতে বিভক্ত করতে চান। এখানে কিছু উদাহরন:

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

এবং হ্যাঁ, এটি শেষ প্যাটার্নে ত্রি-নেস্টেড দৃser় বক্তব্য।

সম্পর্কিত প্রশ্নগুলি

আরো দেখুন


1
দ্রষ্টব্য যে এটি কেবল অপেক্ষাকৃত সহজ প্রকাশের জন্য কাজ করবে; আমি সমস্ত "প্রকৃত সংখ্যার প্রতিনিধিত্ব করে এমন একটি রেইগেক্স দিয়ে এটি ব্যবহার করার চেষ্টা করে" লুক-ব্যাক গ্রুপের সুস্পষ্ট সর্বোচ্চ দৈর্ঘ্য নেই "have
daveagp

2
অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

30

একটি খুব নিষ্পাপ সমাধান, এতে রেইগেক্স জড়িত না হ'ল আপনার সীমানাটির (একটি ডিলিমিটারের জন্য কমা ধরে নেওয়া) লাইন ধরে স্ট্রিং প্রতিস্থাপন করা হবে:

string.replace(FullString, "," , "~,~")

যেখানে আপনি টিল্ডা (~) একটি উপযুক্ত অনন্য ডিলিমিটারের সাথে প্রতিস্থাপন করতে পারেন।

তারপরে যদি আপনি আপনার নতুন সীমানারটিতে বিভাজন করেন তবে আমি বিশ্বাস করি আপনি পছন্দসই ফলাফল পাবেন।


24
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


ওয়াহু ... অংশগ্রহণের জন্য আপনাকে ধন্যবাদ! আকর্ষণীয় পদ্ধতির। আমি নিশ্চিত নই যে এটি ধারাবাহিকভাবে সহায়তা করা যেতে পারে (এর সাথে, কখনও কখনও একটি ডিলিমিটার থাকে, কখনও কখনও থাকে না), তবে চেষ্টাটির জন্য +1। তবে, আপনাকে এখনও সীমাবদ্ধতার কেসগুলি সঠিকভাবে মোকাবেলা করতে হবে (খালি বা নাল মান)
ভোনসি

আমি আপনাকে এই ক্লাসটিকে যথাযথভাবে চাঙ্গা করার জন্য, পুরোপুরি নথিবদ্ধ করার জন্য, ফাইন্ডব্যাগ এবং চেকস্টাইলের সাথে একটি পাস করার জন্য এবং তারপরে একটি স্নিপেটস ওয়েবসাইটে প্রকাশ করুন (টন কোড দিয়ে এই পৃষ্ঠাটি
গোলমাল

আপনি চ্যালেঞ্জ জিতেছে! এরর ... অভিনন্দন! আপনি কি জানেন যে কোড-চ্যালেঞ্জের থ্রেড থেকে, এর জন্য কোনও বিশেষ পয়েন্ট বা ব্যাজ থাকবে না ... (দীর্ঘশ্বাস): স্ট্যাকওভারফ্লো / প্রশ্ন / 172184 । তবে এই অবদানের জন্য আপনাকে ধন্যবাদ।
ভনসি

@ ভনসি বেশিরভাগ সময়, nullযুক্তির উপর এনপিই নিক্ষেপ করার সঠিক উপায়। নিঃশব্দে পরিচালনা করলে ত্রুটিগুলি পরে দেখা যায়।
মার্টিনাস

@ মার্টিনাস আমি সম্মত, তবে নিশ্চয়ই এমন কোনও উদাহরণ রয়েছে যেখানে আপনি কেবল এনপিইর চেয়ে আরও বেশি ব্যবহারকারী-বান্ধব বার্তা ফেলতে চান, তাই না?
ভোনসি

11

আমি এখানে দেরিতে পৌঁছেছি, তবে আসল প্রশ্নে ফিরে আসছি, কেন শুধু বর্ণমালা ব্যবহার করবেন না?

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

আমি আশা করি এটি পড়া সহজ। মাথা উঁচু করার জন্য ধন্যবাদ, @ ফিনিউ


আমি জানি এটি ভুল দেখাচ্ছে - সত্যের এক বছর পরে যখন আমি এখন এটিতে ফিরে এসেছিলাম তখন এটি আমার কাছে ভুল মনে হয়েছিল। নমুনা ইনপুটটি বাজেভাবে বেছে নেওয়া হয়েছিল; আমি পোস্টটি সম্পাদনা করব এবং বিষয়গুলি স্পষ্ট করার চেষ্টা করব।
অ্যালান মুর

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

10

আমি জানি এটি একটি খুব পুরানো প্রশ্ন এবং উত্তরও গ্রহণ করা হয়েছে। তবে তবুও আমি মূল প্রশ্নের খুব সাধারণ উত্তর জমা দিতে চাই। এই কোডটি বিবেচনা করুন:

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শব্দ সীমানা থেকে ছাড়া যখন এটি লেখার সূচনা।


1
+1 আমার পক্ষে সেরা উত্তর। তবে এটি বর্ণানুক্রমিক স্ট্রিংয়ের অক্ষরে অক্ষরের জন্য কাজ করে না
ক্যাসিমির এবং হিপপলিট

@ ক্যাসিমিরেট হিপপলিট: আপনার উত্থানের জন্য ধন্যবাদ। আপনি দয়া করে একটি নমুনা ইনপুট প্রদান করতে পারেন যেখানে এটি কাজ করে না।
অনুভা

2
উদাহরণস্বরূপ এই জন্য কাজ করে না abcdefসঙ্গে deবিভেদক হিসাবে, কিন্তু আপনি সমস্যা ব্যবহার সমাধান করতে পারে(?!^|$)(?:(?<=de)(?!de)|(?<!de)(?=de))
ক্যাসিমির এবং Hippolyte,

1
ফলাফলটি খালি স্ট্রিং এড়ানোর জন্য প্রথম উক্তিটি নোট করুন যখন ড্রিমিটারের সাথে স্ট্রিংটি শেষ হয়, যেমন(?!^|$)
ক্যাসিমির এবং হিপলপেট

1
অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

9

আমি উপরের উত্তরগুলিতে একবার দেখেছি এবং সত্যই সেগুলির কোনওটিই আমি সন্তুষ্টিকর পাই না। আপনি যা করতে চান তা মূলত পার্ল বিভাজনের কার্যকারিতা নকল করে। জাভা কেন এটিকে অনুমতি দেয় না এবং কোথাও একটি যোগদানের পদ্ধতি () রাখে তা আমার বাইরে নয় তবে আমি খনন করি। এমনকি সত্যিকার অর্থে এর জন্য আপনার কোনও ক্লাসের দরকার নেই। এটি কেবল একটি ফাংশন। এই নমুনা প্রোগ্রামটি চালান:

পূর্বের কিছু উত্তরগুলির অত্যধিক নাল চেকিং রয়েছে, যা আমি সম্প্রতি এখানে একটি প্রশ্নের জবাব লিখেছি:

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

আমি বিভ্রান্ত: জাভাতে একটি বিভাজন () পদ্ধতি রয়েছে, যা পার্লের আদলে তৈরি, তবে অনেক কম শক্তিশালী। এখানে সমস্যাটি হ'ল জাভা বিভক্ত () বিভাজকগণকে ফেরত দেওয়ার কোনও উপায় সরবরাহ করে না, যা আপনি পেরেলের মাধ্যমে প্রথম বন্ধনীগুলি বন্দী করে রেজেক্সকে আবদ্ধ করে পারিলের মধ্যে অর্জন করতে পারেন।
অ্যালান মুর

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

7

আমি স্ট্রিংটোকেনাইজারের ধারণাটি পছন্দ করি কারণ এটি অনুমিত।
তবে এটি অপ্রচলিত এবং স্ট্রিং.স্প্লিট দ্বারা প্রতিস্থাপন করে যা বিরক্তিকর স্ট্রিং ফিরিয়ে দেয় [] (এবং সীমানা যুক্ত করে না)।

সুতরাং আমি একটি স্ট্রিংটোকেনাইজারেক্স প্রয়োগ করলাম যা একটি পরিমার্জনীয় এবং স্ট্রিংকে বিভক্ত করতে সত্যিকারের রেজিএক্সএক্স লাগে।

সত্যিকারের রেগএক্সপ্যাক্ট বলতে বোঝায় যে এটি 'চরিত্রের অনুক্রম' নয় যা ডিলিমিটার গঠনের জন্য পুনরাবৃত্তি হয়:
'ও' কেবল 'ও' এর সাথে মেলে এবং ভিতরে দুটি ফাঁকা স্ট্রিং সহ 'ওও' কে তিনটি ডিলিমিটারে বিভক্ত করবে:

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

তবে "অওব" বিভক্ত করার সময় রিজেক্সএফ ও + প্রত্যাশিত ফলাফলটি ফিরে আসবে

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

এই স্ট্রিংটোকেনাইজারেক্স ব্যবহার করতে:

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

এই শ্রেণীর কোডটি জোন স্নিপেটে উপলভ্য ।

একটি কোড-চ্যালেঞ্জ প্রতিক্রিয়ার জন্য যথারীতি (পরীক্ষার কেসগুলির অন্তর্ভুক্ত একটি স্ব-অন্তর্ভুক্ত শ্রেণি), এটি অনুলিপি করুন (একটি 'src / টেস্ট' ডিরেক্টরিতে) এবং এটি চালান । এর প্রধান () পদ্ধতিটি বিভিন্ন ব্যবহারের চিত্র তুলে ধরে।


দ্রষ্টব্য: (২০০৯ এর শেষের দিকে সম্পাদনা)

নিবন্ধটি চূড়ান্ত চিন্তাগুলি: জাভা পাজলার: স্প্লিটিং হায়ারগুলি বিচিত্র আচরণকে ব্যাখ্যা করার জন্য একটি ভাল কাজ করে String.split()
জোশ ব্লচ এমনকি এই নিবন্ধটির প্রতিক্রিয়াতে মন্তব্য করেছিলেন:

হ্যাঁ, এটি একটি ব্যথা। এফডাব্লুআইডাব্লু, এটি খুব ভাল কারণে করা হয়েছিল: পার্লের সাথে সামঞ্জস্যতা।
যে লোকটি এটি করেছে তারা হলেন মাইক "পাগল" ম্যাকক্লোস্কি, যিনি এখন গুগলে আমাদের সাথে কাজ করেন। মাইক নিশ্চিত করেছে যে জাভার নিয়মিত প্রকাশগুলি 30K পার্ল নিয়মিত প্রকাশের পরীক্ষার প্রত্যেকটিতে কার্যত পাস করেছে (এবং দ্রুত চলেছে)।

গুগলের কমন-লাইব্রেরি পেয়ারাতে একটি স্প্লিটার রয়েছে যা হ'ল:

  • ব্যবহার সহজ
  • গুগল দ্বারা পরিচালিত (এবং আপনার দ্বারা নয়)

সুতরাং এটি চেক আউট মূল্য হতে পারে। তাদের প্রাথমিক রুট ডকুমেন্টেশন (পিডিএফ) থেকে :

জেডিকে রয়েছে:

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

এটি সঠিকভাবে কী করতে চাইলে এটি ব্যবহার করা ভাল: - নিয়মিত প্রকাশ - অ্যারে হিসাবে ফলাফল - খালি খণ্ডগুলি হ্যান্ডল করার উপায়

মিনি-পাজল: ", এ, বি,"। স্প্লিট (",") ফিরে আসে ...

(a) "", "a", "", "b", ""
(b) null, "a", null, "b", null
(c) "a", null, "b"
(d) "a", "b"
(e) None of the above

উত্তর: (ঙ) উপরের কোনটিই নয়।

",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"]

কনফিগার পদ্ধতিগুলির অর্ডারটি কোনও ব্যাপার নয় - বিভাজনের সময়, খালিগুলি যাচাইয়ের আগে ট্রিমিং হয়।


অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

6

"সত্য" হিসাবে তৃতীয় অরগমেন্টটি পাস করুন। এটি পাশাপাশি সীমানা ফেরত দেবে।

StringTokenizer(String str, String delimiters, true);

4

এখানে একটি সহজ পরিষ্কার প্রয়োগ রয়েছে যা সামঞ্জস্যপূর্ণ Pattern#splitএবং পরিবর্তনশীল দৈর্ঘ্যের ধরণগুলির সাথে কাজ করে, যা পিছনে চেহারা সমর্থন করতে পারে না এবং এটি ব্যবহার করা সহজ। এটি @ ক্লেটাস প্রদত্ত সমাধানের মতো।

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করে না, কেন আই আমি পছন্দ করি না উচিত 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);
}

2

আমি আমার কাজের সংস্করণগুলিও পোস্ট করব (প্রথমটি মার্কাসের সাথে সত্যই মিল)।

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

2

একটি রেগেক্স ব্যবহার করে অন্য প্রার্থীর সমাধান। টোকেন ক্রমটি ধরে রেখেছে, এককভাবে একই ধরণের একাধিক টোকেন সঠিকভাবে মেলে। অবক্ষয়টি হ'ল রেগেক্সটি একধরণের বাজে।

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]

1

আমি জাভা এপিআই-তে বিদ্যমান কোনও ক্রিয়াকলাপ সম্পর্কে জানি না যা এটি করে (যা এটি বিদ্যমান নেই বলে মনে হয় না), তবে এখানে আমার নিজস্ব বাস্তবায়ন রয়েছে (এক বা একাধিক ডিলিমিটারগুলি একক টোকেন হিসাবে ফিরে আসবে; আপনি চাইলে প্রতিটি ডিলিমিটারকে আলাদা টোকেন হিসাবে ফিরিয়ে আনতে হবে, এর জন্য কিছুটা অভিযোজন প্রয়োজন হবে:

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

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

1

আমি প্যাটার্ন এবং ম্যাচার ব্যবহার করার পরামর্শ দিচ্ছি, যা আপনি অবশ্যই যা চান তা অবশ্যই অর্জন করবে। আপনার স্ট্রিং.স্প্লিটে আপনি যা ব্যবহার করছেন তার চেয়ে আপনার নিয়মিত অভিব্যক্তিটি কিছুটা জটিল হওয়া দরকার।


+1, এটি সঠিক উপায়। আপনি যদি ক্যাপচার গ্রুপগুলিতে রাখেন তবে স্ট্রিংটোকেনাইজার ডিলিমিটারগুলিকে আউটপুট দেবে, তবে এটি মূলত হ্রাস পেয়েছে। লুপहेডের সাথে বিভক্ত () বিভক্ত ব্যবহারটি হ্যাকি কারণ হিসাবে গ্রহণযোগ্য উত্তরের মন্তব্যে বর্ণিত হয়েছে - মূলত এটি যখন একাধিক ডিলিমিটারের বেশি থাকে তখন গোলযোগ হয়। তবে প্যাটার্ন এবং ম্যাচারের সাথে কয়েকটি লাইনে আপনার আসল টোকেনাইজার থাকতে পারে।
জনসিপ 9

1

আমি এটি দিয়ে সম্ভব বলে মনে করি না String#split, তবে আপনি একটি ব্যবহার করতে পারেন StringTokenizer, যদিও এটি আপনাকে আপনার সীমানাটিকে রেজেক্স হিসাবে সংজ্ঞায়িত করতে দেয় না, তবে কেবল একক-অঙ্কের অক্ষরের শ্রেণি হিসাবে:

new StringTokenizer("Hello, world. Hi!", ",.!", true); // true for returnDelims

আমি আমার ডিলিমিটারগুলি নির্দিষ্ট করতে একটি রেজেক্স সংজ্ঞায়িত করতে পারি না।
ড্যানিয়েল রিকোভস্কি

1
স্ট্রিংটোকেনাইজার যদিও একক-অক্ষর ডিলিমিটারগুলির জন্য কেবল অনুমতি দেয়।
মাইকেল বর্গওয়ার্ট

1

যদি আপনি সামর্থ্য করতে পারেন তবে জাভার প্রতিস্থাপন (চারসিকোয়েন্স টার্গেট, চারসিকোয়েন্স রিপ্লেসমেন্ট) পদ্ধতিটি ব্যবহার করুন এবং এর সাথে বিভক্ত হয়ে অন্য একটি সীমানা পূরণ করুন। উদাহরণ: আমি "বু: এবং: ফু" স্ট্রিংটি বিভক্ত করতে চাই এবং তার ডানহাতে স্ট্রিংয়ে ':' রাখতে চাই।

String str = "boo:and:foo";
str = str.replace(":","newdelimiter:");
String[] tokens = str.split("newdelimiter");

গুরুত্বপূর্ণ দ্রষ্টব্য: আপনার স্ট্রিংয়ে আরও "নতুন ডিজিটালমিটার" না থাকলে এটি কেবলমাত্র কাজ করে! সুতরাং, এটি কোনও সাধারণ সমাধান নয়। তবে যদি আপনি এমন একটি চারসিকোয়েন্স জানেন যা সম্পর্কে আপনি নিশ্চিত হতে পারেন যে এটি স্ট্রিংয়ে কখনও উপস্থিত হবে না, এটি একটি খুব সহজ সমাধান।


অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

0

দ্রুত উত্তর: বিভক্ত করতে physical b এর মতো অ শারীরিক সীমা ব্যবহার করুন। আমি এটি চেষ্টা করে দেখতে চেষ্টা করব এবং এটি কাজ করে কিনা (পিএইচপি এবং জেএসে এটি ব্যবহৃত হয়েছে)।

এটি সম্ভব, এবং ধরণের কাজ, তবে খুব বেশি বিভক্ত হতে পারে। প্রকৃতপক্ষে, এটি আপনার বিভক্ত করতে চাইছে এমন স্ট্রিং এবং আপনার প্রয়োজনীয় ফলাফলের উপর নির্ভর করে। আরও বিশদ দিন, আমরা আপনাকে আরও ভালভাবে সহায়তা করব।

আরেকটি উপায় হ'ল আপনার নিজের বিভক্তিটি করা, ডিলিমিটারটি ক্যাপচার করা (ধরুন এটি ভেরিয়েবল হয়) এবং ফলাফলের পরে এটি যুক্ত করা।

আমার দ্রুত পরীক্ষা:

String str = "'ab','cd','eg'";
String[] stra = str.split("\\b");
for (String s : stra) System.out.print(s + "|");
System.out.println();

ফলাফল:

'|ab|','|cd|','|eg|'|

কিছুটা বেশি ... :-)


অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

0

তালিকায় ম্যাচিং প্যাটার্নটি অন্তর্ভুক্ত করতে প্যাটার্ন.স্প্লিট () টুইট করেছেন

যোগ করা হয়েছে

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

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

0

উপরের কিছু কোডের উপর ভিত্তি করে এখানে একটি গ্রোভি সংস্করণ রয়েছে, যদি এটি সহায়তা করে। এটি ছোট, যাইহোক। শর্তাধীনভাবে মাথা এবং লেজ অন্তর্ভুক্ত থাকে (যদি তারা খালি না থাকে)। শেষ অংশটি একটি ডেমো / পরীক্ষার কেস।

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

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9

0

তবুও কাজ করে এমন একটি অত্যন্ত নিখুঁত এবং অদক্ষ সমাধান U স্ট্রিংয়ে দু'বার বিভক্ত করুন এবং তারপরে দুটি অ্যারে যুক্ত করুন

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

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

Scanner scanner = new Scanner("((A+B)*C-D)*E"); scanner.useDelimiter("((?<=[\\+\\*\\-\\/\\(\\)])|(?=[\\+\\*\\-\\/\\(\\)]))"); while (scanner.hasNext()) { System.out.print(" " + scanner.next()); }
রিজেপসপ

0

এই প্রশ্নের একটি সূক্ষ্মতার মধ্যে একটি "শীর্ষস্থানীয় ডিলিমিটার" প্রশ্নের সাথে জড়িত: আপনি যদি টোকেন এবং ডিলিমিটরগুলির সম্মিলিত অ্যারে পেতে চলেছেন তবে আপনাকে তা জানতে হবে এটি একটি টোকেন বা ডিলিমিটার দিয়ে শুরু হয় কিনা। আপনি অবশ্যই ধরে নিতে পারেন যে একটি অগ্রণী ডিলিম ফেলে দেওয়া উচিত তবে এটি একটি অযৌক্তিক অনুমান বলে মনে হচ্ছে। আপনিও জানতে চাইতে পারেন আপনার ট্রেলিং ডিলিম আছে কি না। এটি সেই অনুযায়ী দুটি বুলিয়ান পতাকা সেট করে।

গ্রোভিতে লেখা তবে জাভা সংস্করণটি মোটামুটি সুস্পষ্ট হওয়া উচিত:

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

            }

-2

আমি জাভা খুব ভাল জানি না, তবে আপনি যদি এমন কোনও স্প্লিট পদ্ধতি খুঁজে না পান তবে আমি আপনাকে নিজের তৈরি করার পরামর্শ দিই।

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

এটি খুব মার্জিত নয়, তবে তা করবে।


তবে আপনার যদি একাধারে একাধিক সীমানা সরবরাহকারী থাকে?
কিপ

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/275768/...
Shog9
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.