জাভা একাধিক বিভিন্ন স্ট্রিং প্রতিস্থাপন করে একবারে (বা সবচেয়ে দক্ষ উপায়ে)


97

আমার বেশ কয়েকটি দক্ষ উপায়ে স্ট্রিংয়ে বিভিন্ন সাব-স্ট্রিং প্রতিস্থাপন করতে হবে। স্ট্রিং.রেপ্লেস ব্যবহার করে প্রতিটি ক্ষেত্রের প্রতিস্থাপনের পরে আর কোনও উপায় আছে কি?

উত্তর:


102

আপনি যে স্ট্রিংটি চালাচ্ছেন এটি যদি খুব দীর্ঘ হয় বা আপনি অনেকগুলি স্ট্রিং ব্যবহার করছেন তবে জাভা.ইটিল.রেজেক্স.ম্যাচার ব্যবহার করে এটি সার্থক হতে পারে (এটি সংকলনের জন্য আপ-ফ্রন্টের সময় প্রয়োজন, সুতরাং এটি কার্যকর হবে না) যদি আপনার ইনপুট খুব ছোট হয় বা আপনার অনুসন্ধানের প্যাটার্নটি ঘন ঘন পরিবর্তিত হয়)।

নীচে একটি মানচিত্র থেকে নেওয়া টোকেনের তালিকার উপর ভিত্তি করে একটি পূর্ণ উদাহরণ দেওয়া আছে। (অ্যাপাচি কমন্স ল্যাং থেকে স্ট্রিংগটিলগুলি ব্যবহার করে)।

Map<String,String> tokens = new HashMap<String,String>();
tokens.put("cat", "Garfield");
tokens.put("beverage", "coffee");

String template = "%cat% really needs some %beverage%.";

// Create pattern of the format "%(cat|beverage)%"
String patternString = "%(" + StringUtils.join(tokens.keySet(), "|") + ")%";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(template);

StringBuffer sb = new StringBuffer();
while(matcher.find()) {
    matcher.appendReplacement(sb, tokens.get(matcher.group(1)));
}
matcher.appendTail(sb);

System.out.println(sb.toString());

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


4
হ্যাঁ, যদিও পুনরাবৃত্তির সংখ্যার জন্য বেঞ্চমার্ক করা দরকার।
টেকজেন

5
আমি মনে করি আপনার করার আগে প্রতিটি টোকেনের বিশেষ চরিত্রগুলি পালানো উচিত"%(" + StringUtils.join(tokens.keySet(), "|") + ")%";
বিকাশকারী মারিয়াস ইলানাস

লক্ষ্য করুন যে কেউ আরও কিছু গতির জন্য স্ট্রিংবিল্ডার ব্যবহার করতে পারে। স্ট্রিংবিল্ডার সিঙ্ক্রোনাইজ করা হয়নি।
উফস

4
ভবিষ্যতের পাঠক: রেগেক্সের জন্য, "(" এবং ")" সন্ধানের জন্য গোষ্ঠীটি আবদ্ধ করবে। "%" পাঠ্যে আক্ষরিক হিসাবে গণ্য। যদি আপনার পদগুলি শুরু না হয় এবং "%" দিয়ে শেষ হয় তবে সেগুলি পাওয়া যাবে না। সুতরাং উভয় অংশে (পাঠ্য + কোড) উপসর্গ এবং প্রত্যয় সমন্বয় করুন।
লিনাক্সুনিল

67

অ্যালগরিদম

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

সাধারণ কোড

একটি সহজ সমাধান অ্যাপাচি এর নীচে উপকার StringUtils.replaceEachকরে:

  private String testStringUtils(
    final String text, final Map<String, String> definitions ) {
    final String[] keys = keys( definitions );
    final String[] values = values( definitions );

    return StringUtils.replaceEach( text, keys, values );
  }

এটি বড় গ্রন্থগুলিতে ধীর হয়ে যায়।

দ্রুত কোড

বো-এর আহো-করাসিক অ্যালগরিদমের বাস্তবায়ন কিছুটা আরও জটিলতার পরিচয় দিয়েছে যা একই পদ্ধতির স্বাক্ষর সহ একটি ফ্যাডে ব্যবহার করে বাস্তবায়ন বিশদ হয়ে ওঠে:

  private String testBorAhoCorasick(
    final String text, final Map<String, String> definitions ) {
    // Create a buffer sufficiently large that re-allocations are minimized.
    final StringBuilder sb = new StringBuilder( text.length() << 1 );

    final TrieBuilder builder = Trie.builder();
    builder.onlyWholeWords();
    builder.removeOverlaps();

    final String[] keys = keys( definitions );

    for( final String key : keys ) {
      builder.addKeyword( key );
    }

    final Trie trie = builder.build();
    final Collection<Emit> emits = trie.parseText( text );

    int prevIndex = 0;

    for( final Emit emit : emits ) {
      final int matchIndex = emit.getStart();

      sb.append( text.substring( prevIndex, matchIndex ) );
      sb.append( definitions.get( emit.getKeyword() ) );
      prevIndex = emit.getEnd() + 1;
    }

    // Add the remainder of the string (contains no more matches).
    sb.append( text.substring( prevIndex ) );

    return sb.toString();
  }

বেঞ্চমার্ক

মাপদণ্ডের জন্য, বাফারটি নিম্নরূপ এলোমেলো সংখ্যা ব্যবহার করে তৈরি করা হয়েছিল :

  private final static int TEXT_SIZE = 1000;
  private final static int MATCHES_DIVISOR = 10;

  private final static StringBuilder SOURCE
    = new StringBuilder( randomNumeric( TEXT_SIZE ) );

যেখানে MATCHES_DIVISORইনজেক্ট করার জন্য ভেরিয়েবলের সংখ্যা নির্ধারণ করে:

  private void injectVariables( final Map<String, String> definitions ) {
    for( int i = (SOURCE.length() / MATCHES_DIVISOR) + 1; i > 0; i-- ) {
      final int r = current().nextInt( 1, SOURCE.length() );
      SOURCE.insert( r, randomKey( definitions ) );
    }
  }

মানদণ্ডের কোড নিজেই ( জেএমএইচকে ওভারকিল মনে হয়েছিল):

long duration = System.nanoTime();
final String result = testBorAhoCorasick( text, definitions );
duration = System.nanoTime() - duration;
System.out.println( elapsed( duration ) );

1,000,000: 1,000

1,000,000 অক্ষর এবং 1,000 এলোমেলোভাবে স্থানযুক্ত স্ট্রিং সহ একটি সাধারণ মাইক্রো-বেঞ্চমার্ক replace

  • পরীক্ষার স্ট্রিংটুলগুলি: 25 সেকেন্ড, 25533 মিলিস
  • testBorAhoCorasick: 0 সেকেন্ড, 68 মিলিস

কোনো প্রতিযোগিতা নেই.

10,000: 1,000

প্রতিস্থাপনের জন্য 10,000 টি অক্ষর এবং 1000 টি মিলছে স্ট্রিং ব্যবহার করে:

  • টেস্ট স্ট্রিংটুলস: 1 সেকেন্ড, 1402 মিলিস
  • testBorAhoCorasick: 0 সেকেন্ড, 37 মিলি

বিভাজন বন্ধ।

1,000: 10

প্রতিস্থাপনের জন্য 1000 টি অক্ষর এবং 10 টি মিলছে স্ট্রিং ব্যবহার করে:

  • পরীক্ষার স্ট্রিংটুলগুলি: 0 সেকেন্ড, 7 মিলি
  • testBorAhoCorasick: 0 সেকেন্ড, 19 মিলিস

সংক্ষিপ্ত স্ট্রিংগুলির জন্য, আহো-করাসিক স্থাপনের ওভারহেড দ্বারা ব্রুট-ফোর্স পদ্ধতির মাধ্যমে গ্রহন হয় StringUtils.replaceEach

উভয় বাস্তবায়নের সেরাটি পেতে পাঠ্যের দৈর্ঘ্যের উপর ভিত্তি করে একটি সংকর পদ্ধতি সম্ভব।

বাস্তবায়ন

1 এমবি এর চেয়ে বেশি টেক্সটের জন্য অন্যান্য প্রয়োগের তুলনা করার বিষয়টি বিবেচনা করুন:

কাগজপত্র

অ্যালগোরিদম সম্পর্কিত কাগজপত্র এবং তথ্য:


5
নতুন মূল্যবান তথ্য সহ এই প্রশ্নটি আপডেট করার জন্য কুডোস, এটি খুব সুন্দর। আমি মনে করি একটি জেএমএইচ বেঞ্চমার্ক এখনও যথাযথ, কমপক্ষে 10,000: 1,000 এবং 1,000: 10 (JIT কখনও কখনও যাদু অপ্টিমাইজেশান করতে পারে) এর মতো যুক্তিসঙ্গত মানের জন্য।
টুনাকি

builder.onlyWholeWords () সরান এবং এটি স্ট্রিং প্রতিস্থাপনের মতো একইভাবে কাজ করবে।
ওন্দ্রেজ সটোলার

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

একটি দুর্দান্ত পয়েন্ট, @ ভিক্সিডোউলেইউ উত্তর আপডেট করতে যত্নশীল?
ডেভ জারভিস

10

এটি আমার পক্ষে কাজ করেছে:

String result = input.replaceAll("string1|string2|string3","replacementString");

উদাহরণ:

String input = "applemangobananaarefruits";
String result = input.replaceAll("mango|are|ts","-");
System.out.println(result);

আউটপুট: আপেল-কলা-ফ্রুই-


ঠিক আমার বন্ধুদের কী দরকার ছিল :)
GOXR3PLUS

7

আপনি যদি অনেক বার স্ট্রিং পরিবর্তন করতে চলেছেন তবে স্ট্রিংবিল্ডার ব্যবহার করা সাধারণত কার্যকর (তবে এটির জন্য আপনার কার্য সম্পাদনকে মাপুন ) :

String str = "The rain in Spain falls mainly on the plain";
StringBuilder sb = new StringBuilder(str);
// do your replacing in sb - although you'll find this trickier than simply using String
String newStr = sb.toString();

আপনি যখনই কোনও স্ট্রিংয়ের প্রতিস্থাপন করেন, একটি নতুন স্ট্রিং অবজেক্ট তৈরি হয়, কারণ স্ট্রিংগুলি পরিবর্তনযোগ্য নয়। স্ট্রিংবিল্ডার পরিবর্তনীয়, অর্থাৎ এটি আপনার পছন্দমতো পরিবর্তন করা যেতে পারে।


আমি ভীত, এটি সাহায্য করে না। যখনই প্রতিস্থাপনটি দৈর্ঘ্যে মূল থেকে পৃথক হয়, আপনার কিছু স্থানান্তর প্রয়োজন, যা নতুনভাবে স্ট্রিং তৈরির চেয়ে ব্যয়বহুল হতে পারে। নাকি আমি কিছু মিস করছি?
মার্টিনাস

4

StringBuilderআরও দক্ষতার সাথে প্রতিস্থাপন সম্পাদন করবে, কারণ এর অক্ষর অ্যারে বাফারটি একটি প্রয়োজনীয় দৈর্ঘ্যে নির্দিষ্ট করা যেতে পারে be StringBuilderসংযোজন চেয়ে আরো জন্য ডিজাইন করা হয়েছে!

অবশ্যই আসল প্রশ্নটি এটি একটি অপ্টিমাইজেশন খুব দূরের কিনা? জেভিএম একাধিক অবজেক্ট তৈরি এবং তারপরে আবর্জনা সংগ্রহের পরিচালনা করতে খুব ভাল, এবং সমস্ত অপ্টিমাইজেশন প্রশ্নের মতো আমার প্রথম প্রশ্নটি আপনি এটি পরিমাপ করেছেন এবং নির্ধারণ করেছেন যে এটি একটি সমস্যা।


2

রিপ্লেসএল () পদ্ধতিটি কীভাবে ব্যবহার করবেন ?


4
অনেকগুলি ভিন্ন সাবস্ট্রিংগুলি একটি রেজিজেটে পরিচালনা করা যায় (/substring1ypesubstring2ype.../)। ওপি কী ধরণের প্রতিস্থাপনের চেষ্টা করছে তার উপর নির্ভর করে।
আভি

4
ওপি আরও কিছু দক্ষতার জন্য সন্ধান করছেstr.replaceAll(search1, replace1).replaceAll(search2, replace2).replaceAll(search3, replace3).replaceAll(search4, replace4)
কিপ

2

রাইথম জাভা টেম্পলেট ইঞ্জিনটি এখন স্ট্রিং ইন্টারপোলেশন মোড নামে একটি নতুন বৈশিষ্ট্য সহ প্রকাশিত হয়েছে যা আপনাকে এরকম কিছু করতে দেয়:

String result = Rythm.render("@name is inviting you", "Diana");

উপরের কেসটি দেখায় আপনি অবস্থান অনুসারে টেমপ্লেটে যুক্তিটি পাস করতে পারেন। রাইথম আপনাকে নামের সাথে যুক্তিগুলিও পাস করার অনুমতি দেয়:

Map<String, Object> args = new HashMap<String, Object>();
args.put("title", "Mr.");
args.put("name", "John");
String result = Rythm.render("Hello @title @name", args);

দ্রষ্টব্য রাইথম অত্যন্ত দ্রুত, স্ট্রিং.ফর্ম্যাট এবং বেগের চেয়ে প্রায় 2 থেকে 3গুণ দ্রুত, কারণ এটি টেমপ্লেটটি জাভা বাইট কোডকে সংকলন করে, রানটাইম পারফরম্যান্স স্ট্রিংবিল্ডারের সাথে একত্রীকরণের খুব কাছে।

লিঙ্কগুলি:


এটি বেগ, জেএসপি এমনকি অনেকগুলি টেম্পলটিং ভাষার সাথে উপলব্ধ খুব পুরানো ক্ষমতা ability এছাড়াও এটি এমন প্রশ্নের উত্তর দেয় না যার জন্য অনুসন্ধানের স্ট্রিংগুলির কোনও পূর্বনির্ধারিত বিন্যাসে থাকা দরকার না।
অ্যাঙ্গসুমান চক্রবর্তী

আকর্ষণীয়, গৃহীত উত্তর একটি উদাহরণ সরবরাহ করে :, "%cat% really needs some %beverage%."; এটি %পৃথক টোকেনকে একটি পূর্বনির্ধারিত ফর্ম্যাটটি নয়? আপনার প্রথম বিষয়টি আরও মজাদার, জেডিকে প্রচুর "পুরানো ক্ষমতা" সরবরাহ করে, এর মধ্যে কয়েকটি 90 এর দশক থেকে শুরু হয়, লোকেরা কেন তাদের ব্যবহার করে বিরক্ত করে? আপনার মন্তব্য এবং ডাউনভোটিং কোনও সত্যিকার অর্থে আসে না
জেলিন লুও

ইতিমধ্যে প্রচুর প্রাক বিদ্যমান টেম্পলেট ইঞ্জিন উপস্থিত থাকলে এবং বুট করার জন্য वेग বা ফ্রিমার্কারের মতো ব্যাপকভাবে ব্যবহৃত হয় তখন রাইথম টেম্পলেট ইঞ্জিনটি প্রবর্তন করার কী দরকার? কোর জাভা কার্যকরীতার চেয়ে পর্যাপ্ত চেয়ে বেশি কেন অন্য পণ্যটির সাথে পরিচয় করান। আমি পারফরম্যান্সে আপনার বক্তব্যকে সত্যই সন্দেহ করি কারণ প্যাটার্নটিও সংকলিত হতে পারে। কিছু আসল নম্বর দেখতে পছন্দ করবেন।
অ্যাঙ্গসুমান চক্রবর্তী

সবুজ, আপনি বিন্দু অনুপস্থিত। প্রশ্নকর্তা নির্বিচারে স্ট্রিংগুলি প্রতিস্থাপন করতে চায় যেখানে আপনার সমাধানটি @ পূর্ববর্তী যেমন পূর্বনির্ধারিত বিন্যাসে কেবল স্ট্রিংকে প্রতিস্থাপন করবে। হ্যাঁ, উদাহরণটি% ব্যবহার করে তবে কেবল উদাহরণস্বরূপ, সীমাবদ্ধ ফ্যাক্টর হিসাবে নয়। সুতরাং আপনি উত্তর প্রশ্নের উত্তর দেয় না এবং তাই নেতিবাচক পয়েন্ট।
অ্যাঙ্গসুমান চক্রবর্তী

2

নীচে টড ওউনের উত্তরের উপর ভিত্তি করে তৈরি করা হয়েছে । এই সমাধানটিতে সমস্যা রয়েছে যে প্রতিস্থাপনগুলিতে নিয়মিত অভিব্যক্তিগুলির বিশেষ অর্থ রয়েছে এমন অক্ষরগুলি থাকে তবে আপনি অপ্রত্যাশিত ফলাফল পেতে পারেন। আমি wantedচ্ছিকভাবে কেস-সংবেদনশীল অনুসন্ধান করতে সক্ষম হতে চেয়েছিলাম। আমি এখানে যা এলাম:

/**
 * Performs simultaneous search/replace of multiple strings. Case Sensitive!
 */
public String replaceMultiple(String target, Map<String, String> replacements) {
  return replaceMultiple(target, replacements, true);
}

/**
 * Performs simultaneous search/replace of multiple strings.
 * 
 * @param target        string to perform replacements on.
 * @param replacements  map where key represents value to search for, and value represents replacem
 * @param caseSensitive whether or not the search is case-sensitive.
 * @return replaced string
 */
public String replaceMultiple(String target, Map<String, String> replacements, boolean caseSensitive) {
  if(target == null || "".equals(target) || replacements == null || replacements.size() == 0)
    return target;

  //if we are doing case-insensitive replacements, we need to make the map case-insensitive--make a new map with all-lower-case keys
  if(!caseSensitive) {
    Map<String, String> altReplacements = new HashMap<String, String>(replacements.size());
    for(String key : replacements.keySet())
      altReplacements.put(key.toLowerCase(), replacements.get(key));

    replacements = altReplacements;
  }

  StringBuilder patternString = new StringBuilder();
  if(!caseSensitive)
    patternString.append("(?i)");

  patternString.append('(');
  boolean first = true;
  for(String key : replacements.keySet()) {
    if(first)
      first = false;
    else
      patternString.append('|');

    patternString.append(Pattern.quote(key));
  }
  patternString.append(')');

  Pattern pattern = Pattern.compile(patternString.toString());
  Matcher matcher = pattern.matcher(target);

  StringBuffer res = new StringBuffer();
  while(matcher.find()) {
    String match = matcher.group(1);
    if(!caseSensitive)
      match = match.toLowerCase();
    matcher.appendReplacement(res, replacements.get(match));
  }
  matcher.appendTail(res);

  return res.toString();
}

এখানে আমার ইউনিট পরীক্ষার মামলাগুলি রয়েছে:

@Test
public void replaceMultipleTest() {
  assertNull(ExtStringUtils.replaceMultiple(null, null));
  assertNull(ExtStringUtils.replaceMultiple(null, Collections.<String, String>emptyMap()));
  assertEquals("", ExtStringUtils.replaceMultiple("", null));
  assertEquals("", ExtStringUtils.replaceMultiple("", Collections.<String, String>emptyMap()));

  assertEquals("folks, we are not sane anymore. with me, i promise you, we will burn in flames", ExtStringUtils.replaceMultiple("folks, we are not winning anymore. with me, i promise you, we will win big league", makeMap("win big league", "burn in flames", "winning", "sane")));

  assertEquals("bcaacbbcaacb", ExtStringUtils.replaceMultiple("abccbaabccba", makeMap("a", "b", "b", "c", "c", "a")));
  assertEquals("bcaCBAbcCCBb", ExtStringUtils.replaceMultiple("abcCBAabCCBa", makeMap("a", "b", "b", "c", "c", "a")));
  assertEquals("bcaacbbcaacb", ExtStringUtils.replaceMultiple("abcCBAabCCBa", makeMap("a", "b", "b", "c", "c", "a"), false));

  assertEquals("c colon  backslash temp backslash  star  dot  star ", ExtStringUtils.replaceMultiple("c:\\temp\\*.*", makeMap(".", " dot ", ":", " colon ", "\\", " backslash ", "*", " star "), false));
}

private Map<String, String> makeMap(String ... vals) {
  Map<String, String> map = new HashMap<String, String>(vals.length / 2);
  for(int i = 1; i < vals.length; i+= 2)
    map.put(vals[i-1], vals[i]);
  return map;
}

1
public String replace(String input, Map<String, String> pairs) {
  // Reverse lexic-order of keys is good enough for most cases,
  // as it puts longer words before their prefixes ("tool" before "too").
  // However, there are corner cases, which this algorithm doesn't handle
  // no matter what order of keys you choose, eg. it fails to match "edit"
  // before "bed" in "..bedit.." because "bed" appears first in the input,
  // but "edit" may be the desired longer match. Depends which you prefer.
  final Map<String, String> sorted = 
      new TreeMap<String, String>(Collections.reverseOrder());
  sorted.putAll(pairs);
  final String[] keys = sorted.keySet().toArray(new String[sorted.size()]);
  final String[] vals = sorted.values().toArray(new String[sorted.size()]);
  final int lo = 0, hi = input.length();
  final StringBuilder result = new StringBuilder();
  int s = lo;
  for (int i = s; i < hi; i++) {
    for (int p = 0; p < keys.length; p++) {
      if (input.regionMatches(i, keys[p], 0, keys[p].length())) {
        /* TODO: check for "edit", if this is "bed" in "..bedit.." case,
         * i.e. look ahead for all prioritized/longer keys starting within
         * the current match region; iff found, then ignore match ("bed")
         * and continue search (find "edit" later), else handle match. */
        // if (better-match-overlaps-right-ahead)
        //   continue;
        result.append(input, s, i).append(vals[p]);
        i += keys[p].length();
        s = i--;
      }
    }
  }
  if (s == lo) // no matches? no changes!
    return input;
  return result.append(input, s, hi).toString();
}

1

এটা যাচাই কর:

String.format(str,STR[])

এই ক্ষেত্রে:

String.format( "Put your %s where your %s is", "money", "mouth" );

0

সংক্ষিপ্তসার: দুটি অ্যালগরিদমের মধ্যে স্বয়ংক্রিয়ভাবে সর্বাধিক দক্ষ চয়ন করার জন্য ডেভের উত্তরের একক শ্রেণীর প্রয়োগ।

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

রিপ্লেস স্ট্রিংস ক্লাস:

package somepackage

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.ahocorasick.trie.Emit;
import org.ahocorasick.trie.Trie;
import org.ahocorasick.trie.Trie.TrieBuilder;
import org.apache.commons.lang3.StringUtils;

/**
 * ReplaceStrings, This class is used to replace multiple strings in a section of text, with high
 * time efficiency. The chosen algorithms were adapted from: https://stackoverflow.com/a/40836618
 */
public final class ReplaceStrings {

    /**
     * replace, This replaces multiple strings in a section of text, according to the supplied
     * search and replace definitions. For maximum efficiency, this will automatically choose
     * between two possible replacement algorithms.
     *
     * Performance note: If it is known in advance that the source text is long, then this method
     * signature has a very small additional performance advantage over the other method signature.
     * (Although either method signature will still choose the best algorithm.)
     */
    public static String replace(
        final String sourceText, final Map<String, String> searchReplaceDefinitions) {
        final boolean useLongAlgorithm
            = (sourceText.length() > 1000 || searchReplaceDefinitions.size() > 25);
        if (useLongAlgorithm) {
            // No parameter adaptations are needed for the long algorithm.
            return replaceUsing_AhoCorasickAlgorithm(sourceText, searchReplaceDefinitions);
        } else {
            // Create search and replace arrays, which are needed by the short algorithm.
            final ArrayList<String> searchList = new ArrayList<>();
            final ArrayList<String> replaceList = new ArrayList<>();
            final Set<Map.Entry<String, String>> allEntries = searchReplaceDefinitions.entrySet();
            for (Map.Entry<String, String> entry : allEntries) {
                searchList.add(entry.getKey());
                replaceList.add(entry.getValue());
            }
            return replaceUsing_StringUtilsAlgorithm(sourceText, searchList, replaceList);
        }
    }

    /**
     * replace, This replaces multiple strings in a section of text, according to the supplied
     * search strings and replacement strings. For maximum efficiency, this will automatically
     * choose between two possible replacement algorithms.
     *
     * Performance note: If it is known in advance that the source text is short, then this method
     * signature has a very small additional performance advantage over the other method signature.
     * (Although either method signature will still choose the best algorithm.)
     */
    public static String replace(final String sourceText,
        final ArrayList<String> searchList, final ArrayList<String> replacementList) {
        if (searchList.size() != replacementList.size()) {
            throw new RuntimeException("ReplaceStrings.replace(), "
                + "The search list and the replacement list must be the same size.");
        }
        final boolean useLongAlgorithm = (sourceText.length() > 1000 || searchList.size() > 25);
        if (useLongAlgorithm) {
            // Create a definitions map, which is needed by the long algorithm.
            HashMap<String, String> definitions = new HashMap<>();
            final int searchListLength = searchList.size();
            for (int index = 0; index < searchListLength; ++index) {
                definitions.put(searchList.get(index), replacementList.get(index));
            }
            return replaceUsing_AhoCorasickAlgorithm(sourceText, definitions);
        } else {
            // No parameter adaptations are needed for the short algorithm.
            return replaceUsing_StringUtilsAlgorithm(sourceText, searchList, replacementList);
        }
    }

    /**
     * replaceUsing_StringUtilsAlgorithm, This is a string replacement algorithm that is most
     * efficient for sourceText under 1000 characters, and less than 25 search strings.
     */
    private static String replaceUsing_StringUtilsAlgorithm(final String sourceText,
        final ArrayList<String> searchList, final ArrayList<String> replacementList) {
        final String[] searchArray = searchList.toArray(new String[]{});
        final String[] replacementArray = replacementList.toArray(new String[]{});
        return StringUtils.replaceEach(sourceText, searchArray, replacementArray);
    }

    /**
     * replaceUsing_AhoCorasickAlgorithm, This is a string replacement algorithm that is most
     * efficient for sourceText over 1000 characters, or large lists of search strings.
     */
    private static String replaceUsing_AhoCorasickAlgorithm(final String sourceText,
        final Map<String, String> searchReplaceDefinitions) {
        // Create a buffer sufficiently large that re-allocations are minimized.
        final StringBuilder sb = new StringBuilder(sourceText.length() << 1);
        final TrieBuilder builder = Trie.builder();
        builder.onlyWholeWords();
        builder.ignoreOverlaps();
        for (final String key : searchReplaceDefinitions.keySet()) {
            builder.addKeyword(key);
        }
        final Trie trie = builder.build();
        final Collection<Emit> emits = trie.parseText(sourceText);
        int prevIndex = 0;
        for (final Emit emit : emits) {
            final int matchIndex = emit.getStart();

            sb.append(sourceText.substring(prevIndex, matchIndex));
            sb.append(searchReplaceDefinitions.get(emit.getKeyword()));
            prevIndex = emit.getEnd() + 1;
        }
        // Add the remainder of the string (contains no more matches).
        sb.append(sourceText.substring(prevIndex));
        return sb.toString();
    }

    /**
     * main, This contains some test and example code.
     */
    public static void main(String[] args) {
        String shortSource = "The quick brown fox jumped over something. ";
        StringBuilder longSourceBuilder = new StringBuilder();
        for (int i = 0; i < 50; ++i) {
            longSourceBuilder.append(shortSource);
        }
        String longSource = longSourceBuilder.toString();
        HashMap<String, String> searchReplaceMap = new HashMap<>();
        ArrayList<String> searchList = new ArrayList<>();
        ArrayList<String> replaceList = new ArrayList<>();
        searchReplaceMap.put("fox", "grasshopper");
        searchReplaceMap.put("something", "the mountain");
        searchList.add("fox");
        replaceList.add("grasshopper");
        searchList.add("something");
        replaceList.add("the mountain");
        String shortResultUsingArrays = replace(shortSource, searchList, replaceList);
        String shortResultUsingMap = replace(shortSource, searchReplaceMap);
        String longResultUsingArrays = replace(longSource, searchList, replaceList);
        String longResultUsingMap = replace(longSource, searchReplaceMap);
        System.out.println(shortResultUsingArrays);
        System.out.println("----------------------------------------------");
        System.out.println(shortResultUsingMap);
        System.out.println("----------------------------------------------");
        System.out.println(longResultUsingArrays);
        System.out.println("----------------------------------------------");
        System.out.println(longResultUsingMap);
        System.out.println("----------------------------------------------");
    }
}

প্রয়োজনীয় মাভেন নির্ভরতা:

(প্রয়োজনে এগুলি আপনার পোম ফাইলে যুক্ত করুন))

    <!-- Apache Commons utilities. Super commonly used utilities.
    https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.10</version>
    </dependency>

    <!-- ahocorasick, An algorithm used for efficient searching and 
    replacing of multiple strings.
    https://mvnrepository.com/artifact/org.ahocorasick/ahocorasick -->
    <dependency>
        <groupId>org.ahocorasick</groupId>
        <artifactId>ahocorasick</artifactId>
        <version>0.4.0</version>
    </dependency>
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.