에서 욕심없는 패턴 (정규 표현식) 일치를 원합니다 awk
. 예를 들면 다음과 같습니다.
echo "@article{gjn, Author = {Grzegorz J. Nalepa}, " | awk '{ sub(/@.*,/,""); print }'
더 짧은 문자열을 선택하는 정규식을 작성할 수 있습니까?
@article{gjn,
이 긴 문자열 대신에? :
@article{gjn, Author = {Grzegorz J. Nalepa},
이 결과를 얻고 싶습니다 :
Author = {Grzegorz J. Nalepa},
다른 예가 있습니다.
echo " , 기사 {gjn, 저자 = {Grzegorz J. Nalepa},"| awk '{sub (/ , [^,] *, /, ""); 인쇄} ' ↑ ^^^^^^^
내가 변경된 것을 참고 @
쉼표 (문자를 ,
입력 문자열과 정규 표현식 모두의 첫 번째 위치에) 문자 (및 변경 .*
에 [^,]*
). 더 짧은 문자열을 선택하는 정규식을 작성할 수 있습니까?
, Author = {Grzegorz J. Nalepa},
더 긴 문자열 대신에? :
,article{gjn, Author = {Grzegorz J. Nalepa},
이 결과를 얻고 싶습니다 :
,article{gjn
답변
그 후 @
첫 번째 를 선택하려면 다음 과 ,
같이 지정해야합니다.@[^,]*,
그 @
뒤에는 *
쉼표 ( [^,]
) 가 아닌 임의의 수 ( )가 옵니다 ,
.
그 접근 방식은와 동등한 것으로 작동 @.*?,
하지만와 같은 것은 아닙니다 @.*?string
. 그 이후의 것이 단일 문자 이상입니다. 문자를 부정하는 것은 쉽지만 정규 표현식에서 문자열을 부정하는 것은 훨씬 어렵습니다 .
다른 접근 방식은 입력에서 사전 처리하여 입력에서 string
발생하지 않는 문자 를 대체하거나 앞에 추가하는 것 입니다.
gsub(/string/, "\1&") # pre-process
gsub(/@[^\1]*\1string/, "")
gsub(/\1/, "") # revert the pre-processing
입력에 대체 문자 ( \1
위)가 포함되지 않는다고 보장 할 수없는 경우 이스케이프 메커니즘을 사용하는 방법이 있습니다.
gsub(/\1/, "\1\3") # use \1 as the escape character and escape itself as \1\3
# in case it's present in the input
gsub(/\2/, "\1\4") # use \2 as our maker character and escape it
# as \1\4 in case it's present in the input
gsub(/string/, "\2&") # mark the "string" occurrences
gsub(/@[^\2]*\2string/, "")
# then roll back the marking and escaping
gsub(/\2/, "")
gsub(/\1\4/, "\2")
gsub(/\1\3/, "\1")
그것은 fixed에서는 작동 string
하지만와 동등한 임의의 정규 표현식에는 작동 하지 않습니다 @.*?foo.bar
.
답변
awk
욕심없는 일치를 수행 할 수없는 해결 방법을 제공하는 몇 가지 좋은 답변이 이미 있으므로 Perl Compatible Regular Expressions (PCRE)를 사용하여 다른 방법으로 정보를 제공하고 있습니다. 명령 행 옵션 awk
을 perl
사용하여 가장 간단한 “일치 및 인쇄” 스크립트를 쉽게 다시 구현할 -n
수 있으며 a2p Awk를 Perl 변환기로 더 복잡한 스크립트를 변환 할 수 있습니다 .
Perl 에는 욕심없는 연산자가 있으며 Perl 스크립트 및 PCRE를 사용하는 모든 것에 사용할 수 있습니다. 예를 들어 GNU grep의 -P
옵션 에서도 구현됩니다 .
PCRE는 Perl의 정규식 과 동일하지 않지만 매우 가깝습니다. 매우 빠르며 확장 정규 표현식에 대한 Perl 향상 기능이 매우 유용하기 때문에 많은 프로그램에서 일반 표현식 라이브러리로 널리 사용됩니다.
로부터 perlre (1) 매뉴얼 페이지
By default, a quantified subpattern is "greedy", that is, it will match
as many times as possible (given a particular starting location) while
still allowing the rest of the pattern to match. If you want it to
match the minimum number of times possible, follow the quantifier with
a "?". Note that the meanings don't change, just the "greediness":
*? Match 0 or more times, not greedily
+? Match 1 or more times, not greedily
?? Match 0 or 1 time, not greedily
{n}? Match exactly n times, not greedily (redundant)
{n,}? Match at least n times, not greedily
{n,m}? Match at least n but not more than m times, not greedily
답변
이 게시물은 오래된 게시물이지만 다음 정보는 다른 사람에게 유용 할 수 있습니다.
awk에서 욕심없는 RE 매칭을 수행하는 방법은 명백하게 조잡합니다. 기본 아이디어는 match (string, RE) 함수를 사용하고 일치하지 않을 때까지 (예상치 않은) 문자열 크기를 점진적으로 줄이는 것입니다.
if (match(string, RE)) {
rstart = RSTART
for (i=RLENGTH; i>=1; i--)
if (!(match(substr(string,1,rstart+i-1), RE))) break;
# At this point, the non-greedy match will start at rstart
# for a length of i+1
}
답변
일반적인 표현의 경우 이것은 욕심없는 일치로 사용할 수 있습니다.
function smatch(s, r) {
if (match(s, r)) {
m = RSTART
do {
n = RLENGTH
} while (match(substr(s, m, n - 1), r))
RSTART = m
RLENGTH = n
return RSTART
} else return 0
}
@JimMellander의 답변을 기반으로 이것을 사용하고 있습니다. smatch
다음과 같이 동작합니다 match
.
s
정규식이r
발생 하는 위치 , 그렇지 않은 경우는 0 변수RSTART
와는RLENGTH
일치하는 문자열의 위치 및 길이로 설정된다.
답변
욕심없는 매칭을하는 방법은 없습니다. 그래도 원하는 출력을 얻을 수 있습니다. sch의 제안은 해당 라인에서 작동합니다. 쉼표를 사용할 수 없지만 “저자”가 항상 원하는 것의 시작 인 경우 다음을 수행 할 수 있습니다.
awk '{ sub(/@.*Author/,"Author"); print }'
Author 앞에 오는 문자 수가 항상 같은 경우 다음을 수행 할 수 있습니다.
awk '{ sub(/@.{21}/,""); print }'
전체 세트에서 데이터가 어떻게 보이는지 알아야합니다.
답변
방법은 항상있다. 쉼표를 구분 기호로 사용하면 주어진 문제를 상당히 쉽게 해결할 수 있습니다.
echo "@article{gjn2010jucs, Author = {Grzegorz J. Nalepa}, " |
awk -F, '{sub(/^[ \t]/, "", $2); print $2}'
필드의 수가 다양 할 때 일반적으로 약간 더 나은 것이 필요합니다. 이러한 경우, 중지 단어를 찾는 것은 종종 그 단어를 사용하여 줄에서 무엇이든 잘라낼 수 있기 때문에 돈을 지불합니다. 예제와 관련하여 여기에 정지 단어가 의미하는 바가 있습니다.
echo "@article{gjn2010jucs, Author = {Grzegorz J. Nalepa}, " |
awk '{sub(/.*Author/, "Author", $0); sub(/},.*/, "}", $0); print $0}'
답변
나는 이것이 오래된 게시물이라는 것을 알고있다. 그러나 요청에 따라 awk를 OP로 사용하는 것이 있습니다.
A = @ article {gjn2010jucs, Author = {Grzegorz J. Nalepa},
echo $ A | awk ‘sub (/ @ [^,] * /, “”)’
출력 :
, 저자 = {Grzegorz J. Nalepa},