최근에 발생한 문제가 있습니다. 다음과 같은 형식의 속성 문자열이 있습니다.
"x=1 and y=abc and z=c4g and ..."
일부 속성에는 숫자 값이 있고, 일부는 알파 값이 있고, 일부는 혼합되어 있고, 일부는 날짜 등이 있습니다.
모든 문자열은 처음에 'x=숨값, y=다른 값'을 가져야 하지만 그렇지 않은 문자열도 있습니다. 제가 해야 할 일이 세 가지 있습니다.
x
와 y
가 있는지 확인하기 위해 문자열의 유효성을 검사합니다. x
와 y
의 값을 파싱합니다.상단의 예제를 감안하면 다음과 같은 변수가 생성됩니다:
$x = 1;
$y = "abc";
$remainder = "z=c4g and ..."
내 질문은: 이들을 구문 분석하고 단일 정규식으로 유효성을 검사하는 (합리적으로) 간단한 방법이 있습니까? 즉,:
if ($str =~ /someexpression/)
{
$x = $1;
$y = $2;
$remainder = $3;
}
문자열은 x
와 y
속성으로만 구성될 수 있습니다. 이것은 유효한 문자열입니다.
제 솔루션을 답변으로 게시할 예정이지만 단일 정규식 기본 설정에 맞지 않습니다.
또한 다른 일을 할 때 함께 name = value 쌍으로 this is how I would do it (버전 사용하여 펄 5.10):
use 5.10.0;
use strict;
use warnings;
my %hash;
while(
$string =~ m{
(?: ^ | \G ) # start of string or previous match
\s*
(?<key> \w+ ) # word characters
=
(?<value> \S+ ) # non spaces
\s* # get to the start of the next match
(?: and )?
}xgi
){
$hash{$+{key}} = $+{value};
}
# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};
Tfsnap 펄 (perl)) 에 (최소한 펄 (perl) 의 5.6).
use strict;
use warnings;
my %hash;
while(
$string =~ m{
(?: ^ | \G ) # start of string or previous match
\s*
( \w+ ) = ( \S+ )
\s* # get to the start of the next match
(?: and )?
}xgi
){
$hash{$1} = $2;
}
# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};
이러한 계속 작업을 할 경우 더 많은 데이터를 사용할 수 있다는 이점도 있다.
저는 정규 표현식에 능숙하지는 않지만, 여러분이 찾고 있는 것과 꽤 근접한 것 같습니다:
/x=(.+) and y=([^ ]+)( and (.*))?/
1, $2, $4를 사용하는 것만 빼고요. 사용 중입니다:
my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
"x=yes and y=no",
"z=nox and w=noy");
foreach (@strs) {
if ($_ =~ /x=(.+) and y=([^ ]+)( and (.*))?/) {
$x = $1;
$y = $2;
$remainder = $4;
print "x: $x; y: $y; remainder: $remainder\n";
} else {
print "Failed.\n";
}
}
출력:
x: 1; y: abc; remainder: z=c4g and w=v4l
x: yes; y: no; remainder:
Failed.
물론 이것은 많은 오류 검사를 생략하고 입력에 대해 모든 것을 알지는 못하지만 이것은 작동하는 것 같습니다.
러드의 버전에 대한 간단한 수정입니다,
/^x=(.+) and y=([^ ]+)(?: and (.*))?/
를 사용하면 $1, $2, $3를 사용할 수 있으며(?: 를 사용하면 캡처하지 않는 그룹이 됩니다), 문자열이 &\'not_x=&\'를 허용하는 대신 &\'x=&\'로 시작하도록 보장합니다.
x 및 y 값이 무엇인지 더 잘 알고 있는 경우 이를 사용하여 정규식을 더 강화해야 합니다:
my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
"x=yes and y=no",
"z=nox and w=noy",
"not-x=nox and y=present",
"x=yes and w='there is no and y=something arg here'");
foreach (@strs) {
if ($_ =~ /^x=(.+) and y=([^ ]+)(?: and (.*))?/) {
$x = $1;
$y = $2;
$remainder = $3;
print "x: {$x}; y: {$y}; remainder: {$remainder}\n";
} else {
print "$_ Failed.\n";
}
}
출력합니다:
x: {1}; y: {abc}; remainder: {z=c4g and w=v4l}
x: {yes}; y: {no}; remainder: {}
z=nox and w=noy Failed.
not-x=nox and y=present Failed.
x: {yes and w='there is no}; y: {something}; remainder: {}
마지막 테스트에서 누락된 부분은 현재 버전의 Y 테스트가 공백을 허용하지 않기 때문이며, X 테스트에 동일한 제한이 있었다면 해당 문자열은 실패했을 것입니다.
러드 및 체비어 다가섰다는 평가를 받고 있지만 대부분 특정 문제를 좁히어 운행에서어떠한 둘 다 가지고 있습니다.
러드 것이 좋습니다.
/ x = (.+), y = ([^] +) (및 (제공합니다.*)? /
체비어 수정날짜 迈向:
/ ^ x, y = ([^] +) = (.+) (?: 그리고 (제공합니다.*)? /
두 번째 버전은 때문에 혼란을 " not_x = foo", 더 나은 않습니다. " 함께, x = foo". 하지만 같은 것을 인정하지 않을 것이고, x = y = z = 표시줄에는 " foo baz". foo " 설정하고 1 달러 = z = bar"; 이는 것은 바람직하지 않다고 말했습니다.
이것은 아마도 너희는너희가 찾고 있다. > ^ x, y = (\w+) = (\w+), / (?: 그리고 (제공합니다.*)? /
이 옵션을 사용하면 할 수 없도록 하고, y = x = 간에, 장소 및 옵션 ". and.". 될 수 있는 3 만달러 에
이 문제를 해결하기 위해 기본적으로 제가 한 일은 다음과 같습니다:
($x_str, $y_str, $remainder) = split(/ and /, $str, 3);
if ($x_str !~ /x=(.*)/)
{
# error
}
$x = $1;
if ($y_str !~ /y=(.*)/)
{
# error
}
$y = $1;
몇 가지 추가 유효성 검사 및 오류 처리는 생략했습니다. 이 기술은 작동하지만 제가 원했던 것만큼 간결하거나 예쁘지는 않습니다. 누군가 더 나은 제안을 해주길 바랍니다.