다음과 같은 정규식이 있다고 가정 해 봅시다. 파일에서 변수 $ regex로로드 했으므로 런타임에 내용을 디자인 타임에 알 수 없습니다. 나는 그것이 "버전 1", "버전 2", "버전 3"와 "버전 4 '라는 이름의 그룹이 포함되어 있음을 발견 할 수 있습니다 :Powershell : 정규식 이름의 그룹을 변수로 바꾸기
"Version (?<version1>\d),(?<version2>\d),(?<version3>\d),(?<version4>\d)"
을 ... 그리고 나는 이러한 변수를 가지고 :
$version1 = "3"
$version2 = "2"
$version3 = "1"
$version4 = "0"
을 .. . 그리고 파일의 다음 문자열을 발견했습니다.
Version 7,7,0,0
... ($ input -match $ regex) 변수가 $ true로 평가되도록 변수 $ input에 저장됩니다.
$ regex에 나타나는 순서를 모르는 경우 어떻게 $ input 문자열의 $ regex에있는 명명 된 그룹을 $ version1, $ version2, $ version3, $ version4의 값으로 바꿀 수 있습니까? $ regex에는 이러한 명명 된 그룹이 포함됨을 알 수 있습니까?)
일치하는 색인으로 그룹 이름을 사용하여 이름이 지정된 그룹을 변수 값으로 대체하는 구문을 설명하는 참조를 찾을 수 없습니다. 심지어 지원됩니까?
편집 : 명확히하기 - 목표는 주어진 파일의 버전 문자열 버전 필드의 변수 번호의 교체를 필요로 텍스트 파일의 모든 종류의 템플릿 버전 문자열을 대체하는 것입니다 (2, 3이 될 수 또는 4 개의 필드 모두). 예를 들어, 파일의 텍스트는 이들의 모습 수있다 (그러나 이들에 제한되지 않는다) :
#define SOME_MACRO(4, 1, 0, 0)
Version "1.2.3.4"
SomeStruct vs = { 99,99,99,99 }
사용자는 함께 필드를 포함하는 행과 일치하는 파일 세트와 정규 표현식을 지정할 수 있습니다 원래 아이디어는 개별 필드가 명명 된 그룹에 포착된다는 것입니다. 이 유틸리티에는 파일에서 대체해야하는 개별 버전 필드 값이 있지만 대체가 포함될 행의 원래 형식을 보존하고 요청 된 필드 만 대체해야합니다.
편집-2 : 나는 내가 성냥의 각각의 위치와 정도에 따라 문자열 계산에 필요로하는 결과를 얻을 수 있다고 생각하지만, 파워 쉘의 교체 작업이 좀 작업을 저장 거라고 기대했다.
편집-3 : 정확하고 간결하게 아래에 설명 안스로 그래서, 거기에만 원래의 입력 문자열, 당신은 단지라는 이름의 그룹을 알고있는에 대해 정규 표현식을 사용하는 방법은 (이 아니며, 그 결과 "-replace"연산 (또는 다른 regex 연산)을 사용하여 명명 된 그룹의 캡처를 대체하고 원래 문자열의 나머지 부분은 그대로 둡니다. 이 문제에 대해 궁금한 사람이 있으면 아래 해결 방법을 사용하게되었습니다. YMMV, 다른 솔루션 가능. 그의 의견과 옵션을 제공 한 Ansgar에게 많은 감사를드립니다.다음 코드 블록
:
- $ 입력 교체
- $ 정규식을 수행 될 한 줄의 텍스트가이 파일로부터 판독 (입력 여기서 문자열])는 정규식 지원되는 명명 된 그룹 중 하나 이상을 포함하는 것으로 확인 된 코드
- $ 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
이것은 좋을 것이라고 동의하지만 사용자가 정규식과 파일 세트를 지정하는 유틸리티를위한 것입니다. 정규식을 알지 못하고 파일 내용이 어떤 모양인지 모르기 때문에 원본 파일 내용을 다시 포맷하지 않으면 첫 번째 줄을 사용할 수 없으므로 바람직하지 않습니다. 나중에 파일 내용을 동일하게 유지하면서 일치하는 행의 부분 문자열 만 개별 버전 필드로 대체해야합니다. – Hoobajoob
아마도 정규식의 명명 된 그룹을 실제 이전/새 번호로 바꾼 다음 문자열 바꾸기를 수행 할 수 있습니다. 정규식에 명명 된 그룹 이외의 표현식이 포함되어 있으면 올바르게 작동하지 않습니다. –
정규식의 명명 된 그룹이 실제로 정의 된 방법을 미리 알지 못하더라도 (예 : \ d, \ d {2}, \ d +, 리터럴 등을 찾을 수있는 등) . 명명 된 그룹 정의에 대한 몇 가지 제약 조건을 소개하고 정규식 구문에서 하나 이상의 문자와 영숫자를 허용하기 위해 위의 for 루프에서 사용 된 정규 표현식을 변경할 수 있습니다 (예 : 정규식에서 "\\ d"를 for 루프는 "[a-zA-Z0-9 \\ + \. \ * \? \^\ $ \ {\} \ | \ [\]] +"). 여하튼이 방법은 하위 문자열 작업보다 바람직합니다. – Hoobajoob