2012-09-01 24 views
5

कहें कि मेरे पास निम्न की तरह एक नियमित अभिव्यक्ति है, लेकिन मैंने इसे एक फ़ाइल से एक परिवर्तनीय $ regex में लोड किया है, और इसलिए डिजाइन समय पर इसकी कोई जानकारी नहीं है कि इसकी सामग्री क्या है, लेकिन रनटाइम पर मैं खोज कर सकते हैं कि यह "version1", "version2", "version3" और "version4" नाम के समूहों में शामिल हैं:पावरहेल: चर के साथ समूह नामित रेगेक्स को बदलना

"Version (?<version1>\d),(?<version2>\d),(?<version3>\d),(?<version4>\d)" 

... और मुझे इन चरों है:

$version1 = "3" 
$version2 = "2" 
$version3 = "1" 
$version4 = "0" 

.. और मैं एक फ़ाइल में निम्न स्ट्रिंग में आ गया:

Version 7,7,0,0 

... जो एक परिवर्तनीय $ इनपुट में संग्रहीत है, ताकि ($ इनपुट-$ $ regex) $ true का मूल्यांकन हो।

$ version1, $ version2, $ version3, $ version4 के मानों के साथ स्ट्रिंग $ इनपुट में नामित समूहों को $ regex से कैसे बदल सकता है यदि मुझे यह पता नहीं है कि वे $ regex (I केवल इतना पता है कि $ regex इन नामित समूहों को शामिल करता है)?

मुझे किसी नाम समूह को प्रतिस्थापित करने के लिए समूह नाम का उपयोग करके एक चर के मूल्य के साथ नामित समूह को बदलने के लिए वाक्यविन्यास का वर्णन करने के लिए कोई संदर्भ नहीं मिल रहा है - क्या यह भी समर्थित है?

संपादित करें: स्पष्ट करने के लिए - लक्ष्य पाठ फ़ाइल के किसी भी प्रकार जहां एक दिया फाइल में संस्करण स्ट्रिंग संस्करण क्षेत्रों के परिवर्तनशील के प्रतिस्थापन की आवश्यकता में टेम्प्लेटेड संस्करण तार को बदलने के लिए है (2, 3 हो सकता है, या सभी 4 फ़ील्ड)। उदाहरण के लिए, एक फ़ाइल में पाठ इनमें से किसी भी दिखाई दे सकता है (लेकिन इन तक सीमित नहीं है):

#define SOME_MACRO(4, 1, 0, 0) 

Version "1.2.3.4" 

SomeStruct vs = { 99,99,99,99 } 

उपयोगकर्ता के साथ, खेतों युक्त लाइन से मिलान करने के लिए एक फ़ाइल सेट और एक रेगुलर एक्सप्रेशन निर्दिष्ट कर सकते हैं मूल विचार यह है कि अलग-अलग क्षेत्रों को नामित समूहों द्वारा पकड़ा जाएगा। उपयोगिता में अलग-अलग संस्करण फ़ील्ड मान होते हैं जिन्हें फ़ाइल में प्रतिस्थापित किया जाना चाहिए, लेकिन उस रेखा के मूल स्वरूप को संरक्षित करना है जिसमें प्रतिस्थापन होंगे, और केवल अनुरोधित फ़ील्ड को प्रतिस्थापित करें।

संपादित -2: मुझे लगता है कि मैं परिणाम मैं स्थिति और मैचों में से प्रत्येक की सीमा के आधार पर सबस्ट्रिंग गणना के साथ की जरूरत है प्राप्त कर सकते हैं, लेकिन उम्मीद थी Powershell के बदलने के आपरेशन मुझे कुछ काम को बचाने के लिए जा रहा था।

संपादित-3: तो, Ansgar के रूप में सही ढंग से और संक्षेप में नीचे का वर्णन करता है, वहाँ नहीं एक तरह से (केवल मूल इनपुट स्ट्रिंग, एक रेगुलर एक्सप्रेशन जिसके बारे में आप केवल नाम के समूहों पता उपयोग कर रहा है, और जिसके परिणामस्वरूप मैचों) नामित समूहों के कैप्चर के प्रतिस्थापन करने के लिए "-रेप्लेस" ऑपरेशन (या अन्य रेगेक्स ऑपरेशंस) का उपयोग करने के लिए, शेष मूल स्ट्रिंग को बरकरार रखते हुए। इस समस्या के लिए, अगर कोई उत्सुक है, तो मैं नीचे दिए गए समाधान का उपयोग कर समाप्त हुआ। वाईएमएमवी, अन्य समाधान संभव है। उनके प्रतिक्रिया और विकल्पों के लिए Ansgar के लिए बहुत धन्यवाद।

निम्नलिखित कोड ब्लॉक में:

  • $ इनपुट पाठ की एक पंक्ति है जिस पर प्रतिस्थापन किया जाने
  • $ regex है (प्रकार की [स्ट्रिंग]) एक रेगुलर एक्सप्रेशन एक फ़ाइल से पढ़ने है जिसे समर्थित नामित समूहों में से कम से कम एक को सत्यापित करने के लिए सत्यापित किया गया है
  • $ regexToGroupName एक हैश तालिका है जो [regex] :: GetGroupNames द्वारा लौटाए गए सरणी के क्रम के अनुसार क्रमबद्ध समूह नामों की एक सरणी में रेगेक्स स्ट्रिंग को मैप करती है() है, जो बाएँ से सही क्रम जिसमें वे अभिव्यक्ति में प्रदर्शित से मेल खाता है
  • $ groupNameToVersionNumber एक हैश तालिका एक संस्करण संख्या के लिए एक समूह का नाम नक्शे है।

$ regex के भीतर नामित समूहों पर बाधा केवल (मुझे लगता है) कि नामित समूहों के भीतर अभिव्यक्ति घोंसला नहीं जा सकती है, और इनपुट स्ट्रिंग के भीतर सबसे अधिक बार मिलना चाहिए।

# This will give us the index and extent of each substring 
# that we will be replacing (the parts that we will not keep) 
$matchResults = ([regex]$regex).match($input) 

# This will hold substrings from $input that were not captured 
# by any of the supported named groups, as well as the replacement 
# version strings, properly ordered, but will omit substrings captured 
# by the named groups 
$lineParts = @() 
$startingIndex = 0 
foreach ($groupName in $regexToGroupName.$regex) 
{ 
    # Excise the substring leading up to the match for this group... 
    $lineParts = $lineParts + $input.Substring($startingIndex, $matchResults.groups[$groupName].Index - $startingIndex) 

    # Instead of the matched substring, we'll use the substitution 
    $lineParts = $lineParts + $groupNameToVersionNumber.$groupName 

    # Set the starting index of the next substring that we will keep... 
    $startingIndex = $matchResults.groups[$groupName].Index + $matchResults.groups[$groupName].Length 
} 

# Keep the end of the original string (if there's anything left) 
$lineParts = $lineParts + $input.Substring($startingIndex, $input.Length - $startingIndex) 

$newLine = "" 
foreach ($part in $lineParts) 
{ 
    $newLine = $newLine + $part 
} 
$input= $newLine 

उत्तर

4

नियमित अभिव्यक्ति इस तरह से काम नहीं करती हैं, इसलिए आप नहीं कर सकते हैं। सीधे नहीं, कि है।

$oldver = $input -replace $regexp, '$1,$2,$3,$4' 
$newver = $input -replace $oldver, "$Version1,$Version2,$Version3,$Version4" 
: आप संस्करण स्ट्रिंग को निकालने के लिए और फिर एक दूसरे चरण में नए संस्करण तार के साथ कि सबस्ट्रिंग की जगह है (एक और अधिक उपयुक्त नियमित अभिव्यक्ति समूहों भागों आप करना चाहते हैं रखें कि का उपयोग करने का संक्षिप्त रूप) क्या कर सकते हैं

संपादित करें:

तुम भी संरचना पता नहीं है, तो आप उस नियमित अभिव्यक्ति के साथ-साथ निकालने चाहिए।

$version = @($version1, $version2, $version3, $version4) 
$input -match $regexp 
$oldver = $regexp 
$newver = $regexp 
for ($i = 1; $i -le 4; $i++) { 
    $oldver = $oldver -replace "\(\?<version$i>\\d\)", $matches["version$i"] 
    $newver = $newver -replace "\(\?<version$i>\\d\)", $version[$i-1] 
} 
$input -replace $oldver, $newver 
+0

सहमत हैं कि यह अच्छा होगा, लेकिन यह एक उपयोगिता के लिए है जहां उपयोगकर्ता रेगेक्स और फ़ाइल सेट निर्दिष्ट करते हैं। मुझे regex नहीं पता है, और मुझे नहीं पता कि फ़ाइल सामग्री कैसा दिखता है, इसलिए मैं मूल फ़ाइल सामग्री को दोबारा सुधार किए बिना आपके उत्तर में पहली पंक्ति का उपयोग नहीं कर सका, जो अवांछित होगा। मुझे फ़ाइल सामग्री को उसी संस्करण को छोड़ना होगा, केवल अलग-अलग संस्करण फ़ील्ड के साथ मेल खाने वाली लाइनों पर केवल सबस्ट्रिंग को बदलना होगा। – Hoobajoob

+0

शायद आप नामित समूहों को वास्तविक अभिव्यक्ति में वास्तविक पुरानी/नई संख्याओं के साथ प्रतिस्थापित कर सकते हैं और फिर स्ट्रिंग को प्रतिस्थापित कर सकते हैं। यदि नियमित अभिव्यक्ति में नामित समूहों के अलावा अन्य अभिव्यक्तियां हैं, तो यह सही तरीके से काम नहीं करेगा। –

+0

यह लगभग काम करता है, हालांकि मुझे पहले से पता नहीं है कि रेगेक्स में नामित समूह वास्तव में परिभाषित किए गए हैं (उदाहरण के लिए, वे \ d, \ d {2}, \ d +, एक शाब्दिक, आदि की तलाश में हो सकते हैं) । मैं नामित समूह परिभाषा पर कुछ बाधाओं को पेश कर सकता हूं और रेज़िक्स सिंटैक्स से एक या अधिक वर्णों को स्वीकार करने के लिए ऊपर दिए गए लूप में उपयोग किए गए रेगेक्स को बदल सकता हूं, साथ ही अल्फान्यूमेरिक (उदाहरण के लिए, "\\ d" को रेगेक्स में बदल दें लूप के लिए "[a-zA-Z0 -9 \\ + \। \ * \? \^\ $ \ {\} \ | \ [\]] +")। किसी भी दर पर, यह दृष्टिकोण संचालन घटाने के लिए बेहतर है। – Hoobajoob

1

सरल समाधान

परिदृश्य में जहाँ आप बस एक संस्करण अपने $input पाठ में कहीं पाया नंबर बदलना चाहते हैं, आप बस ऐसा कर सकता है:

$input -replace '(Version\s+)\d+,\d+,\d+,\d+',"`$1$Version1,$Version2,$Version3,$Version4" 

नाम का उपयोग PowerShell में कब्जा

पुन नामित कैप्चर बारे में अपने प्रश्न garding, कि कर्ली कोष्ठक का उपयोग करके किया जा सकता है। यानी

'dogcatcher' -replace '(?<pet>dog|cat)','I have a pet ${pet}. ' 

देता है:

I have a pet dog. I have a pet cat. cher 

कई कैप्चर से संबंधित समस्या & समाधान

आप एक ही बयान की जगह में एक से अधिक मान को बदल नहीं सकते, प्रतिस्थापन स्ट्रिंग के बाद से सब कुछ के लिए प्रयोग किया जाता है । यानी अगर आपने ऐसा किया:

'dogcatcher' -replace '(?<pet>dog|cat)|(?<singer>cher)','I have a pet ${pet}. I like ${singer}''s songs. ' 

आप प्राप्त करेंगे:

I have a pet dog. I like 's songs. I have a pet cat. I like 's songs. I have a pet . I like cher's songs. 

... जो शायद आप के लिए क्या उम्मीद कर रहे हैं नहीं है।

'dogcatcher' -replace '(?<pet>dog|cat)','I have a pet ${pet}. ' -replace '(?<singer>cher)', 'I like ${singer}''s songs. ' 

... पाने के लिए:

बल्कि, आप आइटम प्रति एक मैच कर दिया था

I have a pet dog. I have a pet cat. I like cher's songs. 

अधिक जटिल समाधान

को यह वापस लाना आपका परिदृश्य, आप वास्तव में कब्जे वाले मूल्यों का उपयोग नहीं कर रहे हैं; बल्कि आप उन रिक्त स्थानों को प्रतिस्थापित करने की उम्मीद कर रहे हैं जो वे नए मानों के साथ थे। उसके लिए, आप बस यह चाहता हूँ चाहते हैं:

$input = 'I''m running Programmer''s Notepad version 2.4.2.1440, and am a big fan. I also have Chrome v 56.0.2924.87 (64-bit).' 

$version1 = 1 
$version2 = 3 
$version3 = 5 
$version4 = 7 

$v1Pattern = '(?<=\bv(?:ersion)?\s+)\d+(?=\.\d+\.\d+\.\d+)' 
$v2Pattern = '(?<=\bv(?:ersion)?\s+\d+\.)\d+(?=\.\d+\.\d+)' 
$v3Pattern = '(?<=\bv(?:ersion)?\s+\d+\.\d+\.)\d+(?=\.\d+)' 
$v4Pattern = '(?<=\bv(?:ersion)?\s+\d+\.\d+\.\d+\.)\d+' 

$input -replace $v1Pattern, $version1 -replace $v2Pattern, $version2 -replace $v3Pattern,$version3 -replace $v4Pattern,$version4 

कौन सा देना होगा:

I'm running Programmer's Notepad version 1.3.5.7, and am a big fan. I also have Chrome v 1.3.5.7 (64-bit). 

एनबी: ऊपर एक 1 लाइनर के रूप में लिखा जा सकता है, लेकिन मैं इसे विभाजित कर दिया है इसे बनाने के लिए पढ़ने के लिए आसान है।

यह रेगेक्स लुकराउंड का लाभ उठाता है; स्ट्रिंग के पहले और बाद में सामग्री को जांचने का एक तरीका, जिसमें आप कैप्चरिंग कर रहे हैं, मैच में शामिल किए बिना। यानी जब हम चुनते हैं कि प्रतिस्थापित करने के लिए हम कह सकते हैं कि "शब्द संस्करण के बाद दिखाई देने वाली संख्या से मेल करें" शब्द के बजाय "शब्द संस्करण को प्रतिस्थापित करें"। उन्हें यहां पर

और जानकारी: http://www.regular-expressions.info/lookaround.html

आपका उदाहरण

ऊपर अनुकूल अपने उदाहरण के लिए काम करने के लिए (यानी जहां संस्करणों अल्पविराम या बिंदु के द्वारा अलग किया जा सकता है, और वहाँ उनके प्रारूप करने के लिए कोई निरंतरता है 4 संख्या के सेट होने के बजाए:

$input = @' 
#define SOME_MACRO(4, 1, 0, 0) 

Version "1.2.3.4" 

SomeStruct vs = { 99,99,99,99 } 
'@ 

$version1 = 1 
$version2 = 3 
$version3 = 5 
$version4 = 7 

$v1Pattern = '(?<=\b)\d+(?=\s*[\.,]\s*\d+\s*[\.,]\s*\d+\s*[\.,]\s*\d+\b)' 
$v2Pattern = '(?<=\b\d+\s*[\.,]\s*)\d+(?=\s*[\.,]\s*\d+\s*[\.,]\s*\d+\b)' 
$v3Pattern = '(?<=\b\d+\s*[\.,]\s*\d+\s*[\.,]\s*)\d+(?=\s*[\.,]\s*\d+\b)' 
$v4Pattern = '(?<=\b\d+\s*[\.,]\s*\d+\s*[\.,]\s*\d+\s*[\.,]\s*)\d+\b' 

$input -replace $v1Pattern, $version1 -replace $v2Pattern, $version2 -replace $v3Pattern,$version3 -replace $v4Pattern,$version4 

देता है:

#define SOME_MACRO(1, 3, 5, 7) 

Version "1.3.5.7" 

SomeStruct vs = { 1,3,5,7 }