স্ট্রিং প্রতিস্থাপনের জন্য কীভাবে রেডেক্সকে এডাব্লুকে দিয়ে ব্যবহার করবেন?


13

ধরুন কোনও ফাইল থেকে এখানে কিছু পাঠ্য রয়েছে:

(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)

আমি প্রতিটি সংখ্যায় 11 যুক্ত করতে চাই এবং তার পরে "প্রতিটি লাইনে একটি থাকে যদি একটি থাকে তবে

(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)

জিএনইউ অ্যাডাব্লু কে এবং রেজেক্স ব্যবহার করে আমার সমাধানটি এখানে দেওয়া হয়েছে:

awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'

অর্থাত, আমি প্রতিস্থাপন করতে চান (\d+)\"সঙ্গে \1+10\", যেখানে \1গ্রুপ প্রতিনিধিত্ব করছে (\d+)। কিন্তু এটি কাজ করে না। আমি কীভাবে এটি কাজ করতে পারি?

গাওক যদি সেরা সমাধান না হয় তবে আর কী ব্যবহার করা যায়?


সদৃশ সম্পর্কে দুঃখিত। তবে আমি প্রথমে স্ট্যাকওভারফ্লোতে জিজ্ঞাসা করেছি, এবং কোনও সন্তোষজনক উত্তর পাইনি, তাই আমি মাইগ্রেশনের জন্য পতাকাঙ্কিত করেছি। তবে এটি কিছু সময়ের জন্য ঘটেনি, তাই আমি এটি হওয়ার আশা করি না এবং তারপরে ইউনিক্স.এসইতে জিজ্ঞাসা করি
টিম

উত্তর:


12

এটি চেষ্টা করুন (গোক প্রয়োজন)

awk '{a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0);if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}' YourFile

আপনার উদাহরণ দিয়ে পরীক্ষা করুন:

kent$  echo '(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 2" "#2")
("Exercises 30" "#30")
("Notes and References 34" "#34"))
)
'|awk '{a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0);if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}'   
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 13" "#13")
("Exercises 41" "#41")
("Notes and References 45" "#45"))
)

মনে রাখবেন যে দুটি সংখ্যা (যেমন 1 "এবং" # 1 ") পৃথক হলে এই আদেশটি কাজ করবে না বা এই প্যাটার্নের সাথে একই লাইনে আরও সংখ্যা রয়েছে (যেমন 23" ... 32 "..." # 123 ") এক লাইনে।


হালনাগাদ

যেহেতু @ টিম (ওপি) বলেছেন যে "একই লাইনে অনুসরণ করা সংখ্যাটি ভিন্ন হতে পারে, তাই আমি আমার আগের সমাধানটিতে কিছু পরিবর্তন করেছি এবং এটি আপনার নতুন উদাহরণের জন্য কার্যকর করে তুলেছি।

বিটিডাব্লু, উদাহরণ থেকে আমি অনুভব করি যে এটি সামগ্রীর কাঠামোর একটি টেবিল হতে পারে, সুতরাং দুটি সংখ্যা কীভাবে আলাদা হতে পারে তা আমি দেখছি না। প্রথমটি হবে মুদ্রিত পৃষ্ঠা নম্বর, এবং দ্বিতীয় # এর সাথে পৃষ্ঠা সূচক হবে। আমি কি সঠিক?

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

awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;}
        a=gensub(/.* ([0-9]+)$/,"\\1","g",$1);
        b=gensub(/([0-9]+)\"/,"\\1","g",$2); 
        gsub(/[0-9]+$/,a+11,$1);
        gsub(/^[0-9]+/,b+11,$2);
        print $1,$2
}' yourFile

আপনার নতুন উদাহরণ দিয়ে পরীক্ষা :

kent$  echo '(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
'|awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;}
        a=gensub(/.* ([0-9]+)$/,"\\1","g",$1);
        b=gensub(/([0-9]+)\"/,"\\1","g",$2); 
        gsub(/[0-9]+$/,a+11,$1);
        gsub(/^[0-9]+/,b+11,$2);
        print $1,$2
}'                        
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)


EDIT2 @ টিমের মন্তব্যের ভিত্তিতে

(1) এফএস = অফস = "\" # "#" এর অর্থ কি ইনপুট এবং আউটপুট উভয় ক্ষেত্রে ক্ষেত্রের বিভাজক দ্বিগুণ উদ্ধৃতি, স্থান, ডাবল উদ্ধৃতি এবং #? দুবার ডাবল উদ্ধৃতি কেন নির্দিষ্ট করবেন?

আপনি ইনপুট এবং আউটপুট উভয় অংশে বিভাজকের পক্ষে ঠিক। এটি পৃথককে সংজ্ঞায়িত করেছে:

" "#

দুটি ডাবল উদ্ধৃতি রয়েছে, কারণ আপনি যে দুটি সংখ্যা চান তা ধরা সহজ (আপনার উদাহরণের ইনপুটের উপর ভিত্তি করে)।

(২) ইন /.* ([০-৯] +) $ /, $ মানে স্ট্রিংটির সমাপ্তি?

একদম ঠিক!

(৩) জিনসুব () এর তৃতীয় যুক্তিতে "জি" এবং "জি" এর মধ্যে পার্থক্য কী? জি এবং জি মধ্যে কোন পার্থক্য নেই। এটা দেখ:

gensub(regexp, replacement, how [, target]) #
    Search the target string target for matches of the regular expression regexp. 
    If "how" is a string beginning with g or G (short for global”), then 
        replace all matches of regexp with replacement.

এটি http://www.gnu.org/s/gawk/manual/html_node/String-Function.html থেকে । আপনি জেনসাবের বিশদ ব্যবহার পেতে পড়তে পারেন।


ধন্যবাদ! আমি ভাবছি কীভাবে এটি তৈরি করা যায় যদি দুটি নম্বর যেমন 1 "এবং" # 1 "আলাদা হয়?
টিম

এই উত্তরটি আপনার বর্তমান পুনঃসংশোধন / উদাহরণের জন্য কাজ করে। যদি প্রয়োজনীয়তাটি পরিবর্তিত হয়, তবে আপনি প্রশ্নটি সম্পাদনা করতে এবং আরও ভাল উদাহরণ দিতে পারেন। এবং আপনার কোড থেকে awk -F'#'মনে হচ্ছে আপনি কেবল '#' এর পরে অংশটি পরিবর্তন করতে চান?
কেন্ট

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

@ টিম আপনার নতুন উদাহরণের জন্য আমার আপডেট হওয়া উত্তরটি দেখুন।
কেন্ট

ধন্যবাদ! কিছু প্রশ্ন: (1) এর FS=OFS="\" \"#"অর্থ কি উভয় ইনপুট এবং আউটপুটে ক্ষেত্রের বিভাজকটি ডাবল উদ্ধৃতি, স্থান, ডাবল উদ্ধৃতি এবং #? দুবার ডাবল উদ্ধৃতি কেন নির্দিষ্ট করবেন? (2) ইন /.* ([0-9]+)$/, $স্ট্রিং এর শেষ মানে? (3) জিনসুব () এর তৃতীয় যুক্তিতে, "g"এবং এর মধ্যে পার্থক্য কী "G"?
টিম

7

Regexp বিকল্পগুলি সরবরাহ করে এমন প্রতিটি সরঞ্জামের থেকে পৃথক, অ্যাডাব্লিক \1প্রতিস্থাপনের পাঠ্যের মতো ব্যাকরেফারেন্সের অনুমতি দেয় না । যদি আপনি ব্যবহার গনুহ awk মিলেছে গোষ্ঠীতে অ্যাক্সেস দেয় matchফাংশন , কিন্তু না ~বা subবা gsub

আরও মনে রাখবেন যে \1সমর্থিত হলেও , আপনার স্নিপেটটি স্ট্রিং সংযোজন করবে +11, একটি সংখ্যার গণনা সম্পাদন করবে না। এছাড়াও, আপনার রিজেপেক্সটি ঠিক ঠিক নয়, আপনি পছন্দ মতো "42""এবং নাও কিছু মিলছেন "#42"

এখানে একটি দারুণ সমাধান (সতর্কতা, অরক্ষিত)'s এটি প্রতি লাইনে কেবল একটি একক প্রতিস্থাপন করে।

awk '
  match($0, /"#[0-9]+"/) {
    n = substr($0, RSTART+2, RLENGTH-3) + 11;
    $0 = substr($0, 1, RSTART+1) n substr($0, RSTART+RLENGTH-1)
  }
  1 {print}'

পার্ল এটি সহজ হবে।

perl -pe 's/(?<="#)[0-9]+(?=")/$1+11/e'

আপনার উত্তরের প্রথম বাক্যটি ঠিক আমি যা খুঁজছিলাম is তবে, আপনি "... প্রতিস্থাপনের পাঠ্যে" বলেছিলেন এমন একটি ফলো-আপ প্রশ্ন উত্থাপন করে: অজক কি নিজেই রেজেক্স প্যাটার্নে ব্যাকরেফারেন্সের অনুমতি দেয়?
ওয়াইল্ডকার্ড

1
@ উইল্ডকার্ড নো, অজড কেবল গোষ্ঠীগুলির উপর নজর রাখে না (আমি উল্লেখ করা জিএনইউ এক্সটেনশন বাদে)।
গিলস 'তাই মন্দ হওয়া বন্ধ করুন'

5

awkএটি করতে পারে, তবে এটি সরাসরি নয়, এমনকি ব্যাক-রেফারেন্সিং ব্যবহার করে। জেনসু আকারে
জিএনইউ অ্যাওকের (আংশিক) ব্যাকরিফারেন্স রয়েছে

উদাহরণগুলি 123"অস্থায়ীভাবে মোড়ানো হয় \x01এবং \x02এগুলিকে অবিস্মরণীয় হিসাবে চিহ্নিত করা হয় (for sub()। Co।)

অথবা আপনি যাওয়ার সাথে সাথে লুপ পরিবর্তনকারী প্রার্থীদের মধ্য দিয়ে যেতে পারলেন, সেক্ষেত্রে ব্যাকরেফারেন্সিং এবং "বন্ধনীর" দরকার নেই; তবে চরিত্রের সূচকের উপর নজর রাখা দরকার।

awk '{$0=gensub(/([0-9]+)\"/, "\x01\\1\"\x02", "g", $0 )
      while ( match($0, /\x01[0-9]+\"\x02/) ) {
        temp=substr( $0, RSTART, RLENGTH )
        numb=substr( temp, 2, RLENGTH-3 ) + 11
        sub( /\x01[0-9]+\"\x02/, numb "\"" ) 
      } print }'

এখানে আরেকটি উপায়, ব্যবহার gensubএবং অ্যারে splitএবং \x01ফিল্ড ডিলিমিটার হিসাবে ( বিভাজনের জন্য ) .. \ x02 গাণিতিক সংযোজনের প্রার্থী হিসাবে একটি অ্যারের উপাদান চিহ্নিত করে।

awk 'BEGIN{ ORS="" } {
     $0=gensub(/([0-9]+)\"/, "\x01\x02\\1\x01\"", "g", $0 )
     split( $0, a, "\x01" )
     for (i=0; i<length(a); i++) { 
       if( substr(a[i],1,1)=="\x02" ) { a[i]=substr(a[i],2) + 11 }
       print a[i]
     } print "\n" }'

ধন্যবাদ! আপনার প্রথম কোডে, (1) এর "\x01\\1\"\x02"অর্থ কী? আমি এখনও বুঝতে পারি না \x01এবং \x02। (2) আগমন কিভাবে ভিন্ন $0দ্বারা gensubএবং $0গত যুক্তি হিসাবে gensub?
টিম

@Tim। হেক্স মান দেয় \x01এবং \x02প্রতিস্থাপক মার্কার হিসাবে ব্যবহৃত হয়। এই মানগুলি কোনও সাধারণ পাঠ্য ফাইলে থাকার সম্ভাবনা খুব কম , সুতরাং এগুলি ব্যবহারের জন্য সমানভাবে "অত্যন্ত" নিরাপদ (যেমন পূর্ব-বিদ্যমানগুলির সাথে সংঘর্ষের মুখোমুখি নয়) .. তারা কেবল অস্থায়ী লেবেল .. পুনরায় দেখুন এটি লিংক স্ট্রিং-ম্যানিপুলেশন ফাংশনগুলি , তবে সংক্ষেপে: এটি (জেনসাব) ফাংশনের ফলাফল হিসাবে পরিবর্তিত স্ট্রিংটি প্রদান করে এবং মূল লক্ষ্য স্ট্রিংটি পরিবর্তন করা হয় না। ... সহজভাবে আসল লক্ষ্যটি পরিবর্তন করে ..$0=gensub(... $0)$0=
পিটার.ও

3

যেহেতু (ছ) বিশদে সমাধানগুলি বেশ জটিল হয়ে গেছে বলে মনে হচ্ছে, আমি পার্লে একটি বিকল্প সমাধান যুক্ত করতে চেয়েছিলাম:

perl -wpe 's/\d+(?=")/$&+11/eg' < in.txt > out.txt

ব্যাখ্যা:

  • বিকল্পটি -wসতর্কতা সক্ষম করে (যা আপনাকে সম্ভাব্য অযাচিত প্রভাব সম্পর্কে সতর্ক করবে)।
  • বিকল্পটি -pকোডের চারপাশে একটি লুপ বোঝায় যা সেড বা অ্যাজকের মতো কাজ করে, প্রতিটি ইনপুট লাইনটি ডিফল্ট ভেরিয়েবলের মধ্যে স্বয়ংক্রিয়ভাবে সংরক্ষণ করে $_,।
  • অপশনটি -eপার্লকে জানায় যে প্রোগ্রামের কোডটি কোনও স্ক্রিপ্ট ফাইলে নয় কমান্ড লাইনে অনুসরণ করছে।
  • কোডটি একটি রেজেক্স সাবস্টিটিউশন ( s/.../.../) অন $_, যেখানে সংখ্যার ক্রম, যদি এটি একটি দ্বারা অনুসরণ করা "হয়, সিকোয়েন্স দ্বারা প্রতিস্থাপন করা হবে, সংযোজন হিসাবে সংখ্যারূপে ব্যাখ্যা করা হবে, যোগ 11।
  • শূন্য প্রস্থ ইতিবাচক বর্ণন সম্মতি কথন (?=pattern) জন্য দেখায় "ম্যাচ সেটিকে গ্রহণ তাই আমরা প্রতিস্থাপন এটা পুনরাবৃত্তি হবে না ছাড়া। $&প্রতিস্থাপনের ম্যাচ ভেরিয়েবলের পরে কেবলমাত্র সংখ্যাটি থাকবে।
  • /eRegex করার পরিবর্তক বলে perlএকটি স্ট্রিং যেমন গ্রহণের কোড হিসেবে প্রতিস্থাপন "চালানো" পরিবর্তে।
  • /gপরিবর্তক লাইনে প্রতি ম্যাচেই তে এটি পুনরায়, "বিশ্বব্যাপী" প্রতিস্থাপন করে তোলে।

ম্যাচ ভেরিয়েবলটি $&দুর্ভাগ্যক্রমে ৫.২০ এর আগে পার্ল সংস্করণগুলিতে কোড সম্পাদনের জন্য ক্ষতিকারক হবে। একটি দ্রুত (এবং আরও জটিল নয়) সমাধানটি গ্রুপিং এবং এর $1পরিবর্তে পিছনের বিষয়টি ব্যবহার করবে:

perl -wpe 's/(\d+)?="/$1+11/eg' < in.txt > out.txt

এবং যদি সামনের দিকের দৃ too় বক্তব্যটি খুব বিভ্রান্ত দেখায় তবে আপনি উদ্ধৃতি চিহ্নটি স্পষ্টভাবে প্রতিস্থাপন করতে পারেন:

perl -wpe 's/(\d+)"/$1+11 . q{"}/eg' < in.txt > out.txt
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.