كيف يمكنني العثور على سلاسل التي تحتوي على غلاف مع بيرل؟
سؤال
أحاول تصفية الآلاف من الملفات، أبحث عن تلك التي تحتوي على ثوابت السلسلة مع حالة مختلطة. هذه السلاسل يمكن تضمينها في مساحة بيضاء، ولكنها قد لا تحتوي على مساحة بيضاء أنفسها. لذا فإن ما يلي (يحتوي UC Chars) مطابقات:
" AString " // leading and trailing spaces together allowed
"AString " // trailing spaces allowed
" AString" // leading spaces allowed
"newString03" // numeric chars allowed
"!stringBIG?" // non-alphanumeric chars allowed
"R" // Single UC is a match
ولكن هذه ليست:
"A String" // not a match because it contains an embedded space
"Foo bar baz" // does not match due to multiple whitespace interruptions
"a_string" // not a match because there are no UC chars
ما زلت أريد أن أتفق مع الخطوط التي تحتوي على حد سواء أنماط:
"ABigString", "a sentence fragment" // need to catch so I find the first case...
أريد استخدام بيرل Regexps، ويفضل أن يقودها ack. أداة سطر الأوامر. بوضوح، W. و W. لن تعمل. يبدو أن س يجب أن تطابق الأحرف غير الفضائية. لا يبدو لي أن أعرف كيفية تضمين متطلبات "حرف العلوي واحد على الأقل لكل سلسلة" ...
ack --match '\"\s*\S+\s*\"'
هو الأقرب الذي حصلت عليه. أحتاج إلى استبدال S +. مع شيئا ما التي تلتقط "حرف واحد على الأقل (ASCII) حرفا (في أي موضع لسلسلة غير بيضاء)".
هذا واضح في البرنامج في C / C ++ (ونعم، بيرل، من الناحية الإجرائية، دون اللجوء إلى Regexps)، أحاول فقط معرفة ما إذا كان هناك تعبير منتظم يمكن أن يفعل نفس الوظيفة.
المحلول
النمط التالي يمر جميع الاختبارات الخاصة بك:
qr/
" # leading single quote
(?! # filter out strings with internal spaces
[^"]* # zero or more non-quotes
[^"\s] # neither a quote nor whitespace
\s+ # internal whitespace
[^"\s] # another non-quote, non-whitespace character
)
[^"]* # zero or more non-quote characters
[A-Z] # at least one uppercase letter
[^"]* # followed by zero or more non-quotes
" # and finally the trailing quote
/x
باستخدام برنامج الاختبار هذا - الذي يستخدم النمط أعلاه دون /x
وبالتالي بدون مسافة بيضاء وتعليقات - كمدخل إلى ack-grep
(كما ack
ويدعى أوبونتو)
#! /usr/bin/perl
my @tests = (
[ q<" AString "> => 1 ],
[ q<"AString "> => 1 ],
[ q<" AString"> => 1 ],
[ q<"newString03"> => 1 ],
[ q<"!stringBIG?"> => 1 ],
[ q<"R"> => 1 ],
[ q<"A String"> => 0 ],
[ q<"a_string"> => 0 ],
[ q<"ABigString", "a sentence fragment"> => 1 ],
[ q<" a String "> => 0 ],
[ q<"Foo bar baz"> => 0 ],
);
my $pattern = qr/"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"/;
for (@tests) {
my($str,$expectMatch) = @$_;
my $matched = $str =~ /$pattern/;
print +($matched xor $expectMatch) ? "FAIL" : "PASS",
": $str\n";
}
تنتج الناتج التالي:
$ ack-grep '"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"' try
[ q<" AString "> => 1 ],
[ q<"AString "> => 1 ],
[ q<" AString"> => 1 ],
[ q<"newString03"> => 1 ],
[ q<"!stringBIG?"> => 1 ],
[ q<"R"> => 1 ],
[ q<"ABigString", "a sentence fragment"> => 1 ],
my $pattern = qr/"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"/;
print +($matched xor $expectMatch) ? "FAIL" : "PASS",
مع قذيفة C والمشتقات، عليك الهروب من الانفجار:
% ack-grep '"(?\![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"' ...
أتمنى أن أتمكن من الحفاظ على المباريات المميزة، لكن هذا لا يبدو أنه مسموح.
لاحظ أن نجا من اقتباسات مزدوجة (\"
) سوف تخلط بين هذا النمط بشدة.
نصائح أخرى
يمكنك إضافة متطلبات فئة حرف، مثل:
ack --match "\"\s*\S+[A-Z]\S+\s*\""
أنا أفترض أن ack
يطابق سطر واحد في وقت واحد. ال \S+\s*\"
جزء يمكن أن يطابق اقتباسات إغلاق متعددة على التوالي. سوف تتطابق مع مجمل "alfa""
, ، بدلا من مجرد "alfa"
.