একক পাসে একাধিক স্ট্রিং প্রতিস্থাপন করুন


11

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

echo "AB" | awk '{gsub("A","B");gsub("B","A");print}'
>> AA

echo "AB" | sed 's/A/B/g;s/B/A/g'
>> AA

এই ক্ষেত্রে সঠিক ফলাফল অবশ্যই বিএ।

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

দ্রষ্টব্য আমি কেবল সঠিক জেনেরিক সমাধানের সন্ধান করছি। দয়া করে নির্দিষ্ট প্রস্তাবনাগুলি (ইনপুট ফাইলগুলি অনুসন্ধান করুন এবং জোড়গুলি প্রতিস্থাপন করুন) এর জন্য ব্যর্থ হওয়া সমাধানগুলি প্রস্তাব করবেন না, তবে সম্ভবত তাদের সম্ভাবনা কম।


আমি ধরে নিই যে তারা একটি চরিত্রের চেয়ে দীর্ঘ? এই জন্য আপনি ব্যবহার করতে পারেন tr AB BA
কেভিন

3
এবং প্রকৃতপক্ষে, কেউ যদি আপনার নোটটিকে কিছুটা অভদ্র মনে করে আমি অবাক হব না।
পিটার্ফ

1
আপনি যখন নমুনা ইনপুট বা আউটপুট সরবরাহ করেন নি তখন আপনি কীভাবে "কেবল সঠিক সমাধানগুলি" পাওয়ার প্রত্যাশা করবেন?
জেসনওয়ারিয়ান

1
আমি আশঙ্কা করছি যে আপনি এটি বর্ণনা করছেন ঠিক তেমনভাবে আপনার প্রয়োজন হবে - শুরু থেকে পার্স করুন এবং আপনি যেমন যান তেমন প্রতিস্থাপন করুন - নিয়মিত প্রকাশের সাথে নয়।
পিটারফ

2
এটি একটি ন্যায্য প্রশ্ন, তবে উত্তরটি হ'ল আপনার একটি স্টেট মেশিন পার্সার প্রয়োজন , যা রিচির উত্তরটি দেয় (সত্য হ্যাকার স্টাইলে, আমি মনে করি)। অন্য কথায়, আপনি কার্যটির জটিলতা অবমূল্যায়ন করছেন, আলা "আমি নিয়মিত প্রকাশের সাথে জেনারালি (এইচটি। এক্স) এমএল পার্স করতে চাই" -> উত্তরটি হয় না। আপনি (কেবল) সেড ব্যবহার করতে পারবেন না । আপনি (জাস্ট) অজানা ব্যবহার করতে পারবেন না । এএফআইএকি-তে কোনও বিদ্যমান সরঞ্জাম নেই যা বাক্সের বাইরে এটি করবে। সানস রিচিদের শোষণ, আপনার কিছু কোড লিখতে হবে।
স্বর্ণিলকস

উত্তর:


10

ঠিক আছে, একটি সাধারণ সমাধান। নিম্নলিখিত বাশ ফাংশন 2kযুক্তি প্রয়োজন ; প্রতিটি জোড়া একটি স্থানধারক এবং একটি প্রতিস্থাপন নিয়ে গঠিত। স্ট্রিংগুলিকে ফাংশনে প্রবেশের জন্য যথাযথভাবে উদ্ধৃতি দেওয়া আপনার পক্ষে। যদি আর্গুমেন্টের সংখ্যাটি বিজোড় হয় তবে একটি অন্তর্নিহিত খালি যুক্তি যুক্ত করা হবে, যা শেষ স্থানধারকের কার্যকারিতা কার্যকরভাবে মুছে ফেলবে।

কোনও স্থানধারক বা প্রতিস্থাপনের মধ্যে NUL টি অক্ষর নাও থাকতে পারে তবে আপনি স্ট্যান্ডার্ড সি- \এস্কেপগুলি ব্যবহার করতে পারেন যেমন \0আপনার প্রয়োজন NUL(এবং ফলস্বরূপ আপনি \\যদি চান তবে আপনাকে লিখতে হবে \)।

এর জন্য স্ট্যান্ডার্ড বিল্ড সরঞ্জাম প্রয়োজন যা একটি পিক্সিক-মতো সিস্টেমে উপস্থিত থাকতে হবে (লেক্স এবং সিসি)।

replaceholder() {
  local dir=$(mktemp -d)
  ( cd "$dir"
    { printf %s\\n "%option 8bit noyywrap nounput" "%%"
      printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
      printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
    } | lex && cc lex.yy.c
  ) && "$dir"/a.out
  rm -fR "$dir"
}

আমরা ধরে নিই যে \আর্গুমেন্টে প্রয়োজনে ইতিমধ্যে পালানো হয়েছে তবে উপস্থিত থাকলে আমাদের ডাবল উদ্ধৃতিগুলি রক্ষা করতে হবে। এটি দ্বিতীয় প্রিন্টফের দ্বিতীয় যুক্তিটি করে। যেহেতু lexডিফল্ট ক্রিয়া হয় ECHOতাই আমাদের এটি নিয়ে চিন্তা করার দরকার নেই।

উদাহরণ রান (সংশয়ীদের জন্য সময় সহ; এটি কেবল একটি সস্তা-ও পণ্য ল্যাপটপ):

$ time echo AB | replaceholder A B B A
BA

real    0m0.128s
user    0m0.106s
sys     0m0.042s
$ time printf %s\\n AB{0000..9999} | replaceholder A B B A > /dev/null

real    0m0.118s
user    0m0.117s
sys     0m0.043s

বৃহত্তর ইনপুটগুলির জন্য এটি একটি অপ্টিমাইজেশন পতাকা প্রদান করতে কার্যকর হতে পারে ccএবং বর্তমান পিক্সিক্সের সামঞ্জস্যের জন্য এটি ব্যবহার করা ভাল c99। আরও উচ্চাভিলাষী বাস্তবায়ন প্রতিটি সময় উত্পন্ন করার পরিবর্তে উত্পন্ন এক্সিকিউটেবলকে ক্যাশে দেওয়ার চেষ্টা করতে পারে তবে এগুলি উত্পন্ন করার পক্ষে মোটেই ব্যয়বহুল নয়।

সম্পাদন করা

আপনার যদি সিসিসি থাকে তবে আপনি একটি অস্থায়ী ডিরেক্টরি তৈরির ঝামেলা এড়াতে পারবেন এবং দ্রুত সংকলনের সময় উপভোগ করতে পারবেন যা সাধারণ আকারের ইনপুটগুলিতে সহায়তা করবে:

treplaceholder () { 
  tcc -run <(
  {
    printf %s\\n "%option 8bit noyywrap nounput" "%%"
    printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
    printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
  } | lex -t)
}

$ time printf %s\\n AB{0000..9999} | treplaceholder A B B A > /dev/null

real    0m0.039s
user    0m0.041s
sys     0m0.031s

আমি নিশ্চিত না এটি কৌতুক কিনা বা না;)
আম্বরোজ বিজজক

3
@ জামরোজবিজাক: এটি কাজ করে, এটি বড় ইনপুটগুলির জন্য দ্রুত এবং ছোট ইনপুটগুলির পক্ষে গ্রহণযোগ্যভাবে দ্রুত। এটি আপনি যে সরঞ্জামগুলির কথা ভাবছিলেন তা ব্যবহার না করে তবে সেগুলি স্ট্যান্ডার্ড সরঞ্জাম। এটি একটি রসিকতা হবে কেন?
ধনী

4
+1 রসিকতা না হওয়ার জন্য! : ডি
স্বর্ণলোকস

এটি পসিক্স পোর্টেবলের মতো হবে fn() { tcc ; } <<CODE\n$(gen code)\nCODE\n। আমি কি জিজ্ঞাসা করতে পারি - এটি একটি দুর্দান্ত উত্তর এবং আমি এটি পড়ার সাথে সাথে এটিকে উত্সাহিত করেছি - তবে শেল অ্যারের কী হচ্ছে তা আমি বুঝতে পারি না? এটি কি করে "${@//\"/\\\"}"?
মাইকজার্ভ

@ মিমকিজার: each প্রতিটি যুক্তির জন্য একটি উদ্ধৃত মান ("$ @") হিসাবে, (/) একটি ব্যাকস্ল্যাশ (\\) এর পরে একটি উদ্ধৃতি (\ ") দিয়ে সমস্ত (//) উদ্ধৃতি ()") প্রতিস্থাপন করুন »। বাশ ম্যানুয়ালটিতে প্যারামিটার সম্প্রসারণ দেখুন।
ধনী

1
printf 'STRING1STRING1\n\nSTRING2STRING1\nSTRING2\n' |
od -A n -t c -v -w1 |
sed 's/ \{1,3\}//;s/\\$/&&/;H;s/.*//;x
     /\nS\nT\nR\nI\nN\nG\n1/s//STRING2/
     /\nS\nT\nR\nI\nN\nG\n2/s//STRING1/
     /\\n/!{x;d};s/\n//g;s/./\\&/g' |
     xargs printf %b

###OUTPUT###

STRING2STRING2

STRING1STRING2
STRING1

এই জাতীয় কিছু যখনই আপনার লক্ষ্যযুক্ত স্ট্রিংগুলির প্রতিটি ঘটনাকে একবার প্রতিস্থাপন করে তবেই তারা sedপ্রতি লাইনে এক কামড়ের প্রবাহে প্রবাহিত হয়। আপনি কল্পনা করতে পারেন এটি এই দ্রুততম উপায়। তারপর আবার, আমি সি লিখুন না কিন্তু এই করে নির্ভরযোগ্যভাবে নাল বিভেদক হ্যান্ডেল যদি আপনি এটি কামনা করি। এটি কীভাবে কাজ করে তার জন্য এই উত্তরটি দেখুন । এই যে কোনো কোন সমস্যা বিশেষ শেল অক্ষর বা অনুরূপ অন্তর্ভুক্ত আছে - কিন্তু এটা হয় হওয়া ASCII লোকেল নির্দিষ্ট, বা, অন্য কথায়, odএকই লাইনে না আউটপুট বহু-বাইট অক্ষর এবং শুধুমাত্র প্রতি এক করতে হবে। যদি সমস্যা হয় তবে আপনি যুক্ত করতে চান iconv


+1 আপনি কেন এটি বলছেন যে এটি কেবল "আপনার টার্গেটের প্রথম দিকের ঘটনা" প্রতিস্থাপন করে? আউটপুটে এটি দেখে মনে হচ্ছে এটি তাদের সমস্তকে প্রতিস্থাপন করে। আমি এটি দেখতে বলছি না, তবে মানগুলি হার্ডকোডিং না করে এভাবেই করা যেতে পারে?
স্বর্ণলোকস

@ গল্ডিলকস - হ্যাঁ - তবে কেবল তা হওয়ার সাথে সাথে। হয়তো আমার উচ্চারিত করা উচিত। এবং হ্যাঁ - আপনি কেবল একটি মাঝখানে যুক্ত করতে পারেন sedএবং নাল বা কিছু সঞ্চয় করতে পারেন তবে sedএইটির লিপিটি লিখতে পারেন ; অথবা এটি শেল "/$1/""/$2/"
ফাংশনটিতে রাখুন এবং

এই ক্ষেত্রে যেখানে প্লেসহোল্ডার হয় কাজ বলে মনে হচ্ছে না PLACE1, PLACE2এবং PLAPLAসবসময় জয়ী. ওপি বলেছেন: " প্রদত্ত প্রতিস্থাপনের স্ট্রিংগুলির মধ্যে একটিতে দীর্ঘতম ম্যাচের জন্য বাম থেকে ডান ইনপুট স্ক্যান করার সমতুল্য " (জোর দেওয়া)
রিচি

@rici - ধন্যবাদ তারপরে আমাকে নাল ডিলিমিটারগুলি করতে হবে। ফিরে একটি ফ্ল্যাশ।
মাইকসার্ভ

টুইট তিনি বলেছেন যে প্রদত্ত প্রতিস্থাপনের একটিতে সবচেয়ে দীর্ঘস্থায়ী । এটি যে। এখানে কোনও ইঙ্গিত নেই যে একটি স্ট্রিং অন্যটির উপসেট, কেবলমাত্র প্রতিস্থাপিত মানটি হতে পারে। আমি মনে করি না যে কোনও লিস্টের মাধ্যমে পুনরাবৃত্তি করা সমস্যা সমাধানের একটি বৈধ উপায়। সমস্যাটি যেমন আমি বুঝতে পেরেছি তা দেওয়া, এটি একটি কার্যকরী সমাধান।
মাইকসার্ভ

1

একটি perlসমাধান। এমনকি যদি কেউ কেউ এটি বলা সম্ভব নাও বলে থাকে তবে আমি একটি পেয়েছি তবে সাধারণভাবে একটি সাধারণ ম্যাচ এবং প্রতিস্থাপন সম্ভব নয় এবং এমনকি এটি আরও খারাপ হয়ে যায় কারণ এনএফএর ব্যাকট্র্যাকিংয়ের ফলে ফলাফল অপ্রত্যাশিত হতে পারে।

সাধারণভাবে এবং এটি অবশ্যই বলা উচিত, সমস্যাটি বিভিন্ন ফলাফলের প্রতিস্থাপন করে যা প্রতিস্থাপন টিউপসগুলির ক্রম এবং দৈর্ঘ্যের উপর নির্ভর করে। অর্থাৎ,

A B
AA CC

এবং ইনপুট AAAফলাফল BBBবা CCB

এখানে কোড:

#!/usr/bin/perl

$v='if (0) {} ';
while (($a,$b)=split /\s+/, <DATA>) {
  $k.=$a.'|';
  $v.='elsif ($& eq \''.$a.'\') {print \''.$b.'\'} ';
}
$k.='.';
$v.='else {print $&;}';

eval "
while (<>) {
  \$_ =~ s/($k)/{$v}/geco;
}";  
print "\n";


__DATA__
A    B
B    A
abba baab
baab abbc
abbc aaba

Checkerbunny:

$ echo 'ABBabbaBBbaabAAabbc'|perl script
$ BAAbaabAAabbcBBaaba
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.