كيف يمكنني مطابقة أي حرف عبر خطوط متعددة في تعبير منتظم؟
سؤال
على سبيل المثال ، هذا regex
(.*)<FooBar>
سيطابق:
abcde<FooBar>
ولكن كيف يمكنني الحصول عليها لتتناسب مع خطوط متعددة؟
abcde
fghij<FooBar>
المحلول
يعتمد ذلك على اللغة ، ولكن يجب أن يكون هناك معدل يمكنك إضافته إلى نمط Regex. في PHP هو:
/(.*)<FooBar>/s
ال س في النهاية يتسبب في مطابقة النقطة الكل شخصيات بما في ذلك الخطوط الجديدة.
نصائح أخرى
جرب هذا:
((.|\n)*)<FooBar>
تقول بشكل أساسي "أي حرف أو سطر جديد" متكرر صفر أو أكثر.
إذا كنت تستخدم Eclipse Search ، فيمكنك تمكين خيار "dotall" لجعل "." تطابق أي حرف بما في ذلك محددات الخط: فقط أضف "(؟ s)" في بداية سلسلة البحث الخاصة بك. مثال:
(?s).*<FooBar>
السؤال هو ، يمكن .
نمط المباراة أي حرف؟ الجواب يختلف من محرك إلى محرك. الفرق الرئيسي هو ما إذا كان يتم استخدام النمط بواسطة مكتبة POSIX أو Non-Posix Regex.
ملاحظة خاصة حول لوا-النباتات: لا تعتبر تعبيرات منتظمة ، ولكن .
يطابق أي char هناك ، مثل محركات Posix القائمة.
ملاحظة أخرى على ماتلاب و أوكتاف: ال .
يطابق أي char افتراضيًا (العرض التوضيحي): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');
(tokens
تحتوي على أ abcde\n fghij
العنصر).
أيضا ، في كل من تعزيز's regex القواعد النقطية تتطابق خط الكسر بشكل افتراضي. تتيح لك Boost's Ecmascript Grammar إيقاف هذا الأمر regex_constants::no_mod_m
(مصدر).
أما بالنسبة لل وحي (إنه يعتمد على Posix) ، والاستخدام n
اختيار (العرض التوضيحي): select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual
المحركات القائمة على Posix:
مجرد .
تطابق بالفعل فترات استراحة الخط ، لا حاجة لاستخدام أي معدلات ، انظر سحق (العرض التوضيحي).
ال TCL (العرض التوضيحي), postgresql (العرض التوضيحي), ص (TRE ، Base R Default Engine بدون perl=TRUE
, ، لقاعدة R مع perl=TRUE
أو ل سلسلة/سلسلة الأنماط ، استخدم (?s)
المعدل المضمن) (العرض التوضيحي) علاج أيضا .
نفس الطريقة.
لكن, ، معظم الأدوات القائمة على POSIX معالجة خط الإدخال سطر. بالتالي، .
لا يتطابق مع انهار الخط لمجرد أنها ليست في نطاق. فيما يلي بعض الأمثلة حول كيفية تجاوز هذا:
- سيد - هناك حلول متعددة ، والأكثر دقة ولكن ليست آمنة للغاية
sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/'
(H;1h;$!d;x;
تملق الملف في الذاكرة). إذا كان يجب تضمين الخطوط الكاملة ،sed '/start_pattern/,/end_pattern/d' file
(ستنتهي الإزالة من البداية مع خطوط متطابقة) أوsed '/start_pattern/,/end_pattern/{{//!d;};}' file
(مع استبعاد خطوط المطابقة) يمكن النظر فيها. - بيرل -
perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str"
(-0
تطفو الملف بأكمله في الذاكرة ،-p
يطبع الملف بعد تطبيق البرنامج النصي المقدم-e
). لاحظ ذلك باستخدام-000pe
سيقوم بتشويش الملف وتنشيط "وضع الفقرة" حيث يستخدم Perl الخطوط الجديدة المتتالية (\n\n
) كما فاصل السجل. - gnu-grep -
grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file
. هنا،z
يمكّن الملف ،(?s)
يتيح وضع dotall ل.
نمط،(?i)
يمكّن الوضع غير الحساس للحالة ،\K
يحذف النص المتطابق حتى الآن ،*?
هو كميات كسول ،(?=<Foobar>)
يطابق الموقع من قبل<Foobar>
. - PCRegrep -
pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file
(M
تمكين الملف الضوضاء هنا). ملحوظةpcregrep
هو حل جيد لنظام التشغيل Mac OSgrep
المستخدمون.
المحركات غير القائمة على بوسيكس:
- بي أتش بي - يستخدم
s
المعدل PCRE_DOTALL المعدل:preg_match('~(.*)<Foobar>~s', $s, $m)
(العرض التوضيحي) - ج# - يستخدم
RegexOptions.Singleline
علَم (العرض التوضيحي):
-var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
-var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
- PowerShell - يستخدم
(?s)
خيار مضمّن:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
- بيرل - يستخدم
s
المعدل (أو(?s)
نسخة مضمنة في البداية) (العرض التوضيحي):/(.*)<FooBar>/s
- بيثون - يستخدم
re.DOTALL
(أوre.S
) أعلام أو(?s)
المعدل المضمن (العرض التوضيحي):m = re.search(r"(.*)<FooBar>", s, flags=re.S)
(وثمif m:
,print(m.group(1))
) - جافا - يستخدم
Pattern.DOTALL
المعدل (أو مضمّن(?s)
علَم) (العرض التوضيحي):Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
- رائع - يستخدم
(?s)
المعدل الداخلي (العرض التوضيحي):regex = /(?s)(.*)<FooBar>/
- سكالا - يستخدم
(?s)
المعدل (العرض التوضيحي):"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
- جافا سكريبت - يستخدم
[^]
أو الحلول[\d\D]
/[\w\W]
/[\s\S]
(العرض التوضيحي):s.match(/([\s\S]*)<FooBar>/)[1]
- C ++ (
std::regex
) يستخدم[\s\S]
أو حلول JS (العرض التوضيحي):regex rex(R"(([\s\S]*)<FooBar>)");
- VBA - استخدم نفس النهج كما في JavaScript ،
([\s\S]*)<Foobar>
. - روبي - يستخدم
/m
متعددة المعدل (العرض التوضيحي):s[/(.*)<Foobar>/m, 1]
- يذهب - استخدم المعدل المضمن
(?s)
في البداية (العرض التوضيحي):re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
- سريع - يستخدم
dotMatchesLineSeparators
أو (أسهل) تمرير(?s)
المعدل المضمون للنمط:let rx = "(?s)(.*)<Foobar>"
- ج موضوعية - مثل سويفت ،
(?s)
يعمل أسهل ، ولكن هنا هو كيف يمكن استخدام الخيار:NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:®exError];
- RE2, Google-Apps-Script - يستخدم
(?s)
المعدل (العرض التوضيحي):"(?s)(.*)<Foobar>"
(في جداول بيانات Google ،=REGEXEXTRACT(A2,"(?s)(.*)<Foobar>")
)
الملاحظات على (?s)
:
في معظم محركات غير بوسيكس ، (?s)
يمكن استخدام المعدل المضمون (أو خيار العلم المدمج) لفرضه .
لمطابقة استراحات الخط.
إذا وضعت في بداية النمط ، (?s)
يغير البهورة للجميع .
في النمط. إذا (?s)
يتم وضعه في مكان ما بعد البداية ، فقط هؤلاء .
سوف تتأثر التي تقع على يمينها ما لم هذا نمط تم تمريره إلى بيثون re
. في بيثون re
, ، بغض النظر عن (?s)
الموقع ، النمط كله .
تتأثر. ال (?s)
توقف التأثير باستخدام (?-s)
. يمكن استخدام مجموعة معدلة للتأثير فقط على نطاق محدد لنمط regex (على سبيل المثال Delim1(?s:.*?)\nDelim2.*
سيجعل الأول .*?
تطابق عبر الخطوط الجديدة والثانية .*
سوف تطابق فقط بقية الخط).
ملاحظة Posix:
في المحركات غير المرسب ، لمطابقة أي شار ، [\s\S]
/ [\d\D]
/ [\w\W]
يمكن استخدام البنيات.
في Posix ، [\s\S]
لا يتطابق مع أي char (كما هو الحال في JavaScript أو أي محرك غير posix) لأن تسلسل regex Escape لا يتم دعمه داخل تعبيرات قوسين. [\s\S]
يتم تحليلها كتعبيرات بين قوسين تتطابق مع شار واحد ، \
أو s
أو S
.
في JavaScript ، استخدم /[\S\s]*<Foobar>/
. مصدر
([\s\S]*)<FooBar>
تتطابق النقطة جميعها باستثناء الخطوط الجديدة ( r n). لذا استخدم s s ، والتي ستتطابق مع جميع الأحرف.
في روبي روبي يمكنك استخدام ال 'm
الخيار (متعدد الأسلحة):
/YOUR_REGEXP/m
نرى وثائق regexp على Ruby-doc.org لمزيد من المعلومات.
يمكننا أيضا استخدام
(.*?\n)*?
لمطابقة كل شيء بما في ذلك الخط الجديد بدون جشع
هذا سيجعل الخط الجديد اختياريًا
(.*?|\n)*?
"."
عادة لا تتطابق مع كسر الخط. تتيح لك معظم محركات Regex إضافة ملف S
-Flag (تسمى أيضًا DOTALL
و SINGLELINE
) ليصنع "."
تطابق أيضا الخطوط الجديدة. إذا فشل ذلك ، يمكنك أن تفعل شيئًا مثل [\S\s]
.
لل Eclipse عملت بعد التعبير:
فو
بار Jadajada "
تعبير عادي:
Foo[\S\s]{1,10}.*Bar*
/(.*)<FooBar>/s
يتسبب S في النقطة (.) لمطابقة عوائد النقل
في التعبير العادي القائم على Java يمكنك استخدامه [\s\S]
لاحظ أن (.|\n)*
يمكن أن تكون أقل كفاءة من (على سبيل المثال) [\s\S]*
(إذا كانت regexes لغتك تدعم مثل هذه الهروب) وإلى العثور على كيفية تحديد المعدل الذي يجعل. تطابق أيضا الخطوط الجديدة. أو يمكنك الذهاب مع بدائل posixy مثل [[:space:][:^space:]]*
.
استخدم regexoptions.singleline ، فهو يغير معنى. لتشمل الخطوط الجديدة
regex.replace (المحتوى ، SearchText ، replacetext ، regexoptions.singleline) ؛
المحلول:
استخدم Modifier Modifier SU الحصول على المطابقة المطلوبة في PHP.
مثال:
preg_match('/(.*)/sU',$content,$match);
مصدر:
http://dreamluverz.com/developers-tools/regex-match-all-including-new-line http://php.net/manual/en/reference.pcre.pattern.modiers.php
في سياق الاستخدام داخل اللغات ، تعمل التعبيرات العادية على الأوتار ، وليس الخطوط. لذلك يجب أن تكون قادرًا على استخدام Regex بشكل طبيعي ، على افتراض أن سلسلة الإدخال لها خطوط متعددة.
في هذه الحالة ، ستطابق Regex المعطى السلسلة بأكملها ، منذ ""u003CFooBar> "يوجد السيطرة على ما إذا كان "". "سوف يتطابق مع الخط الجديد ، مما يمنحك الاختيار.
استخدام التعبير العادي القائم على الخط هو عادة لأشياء خط الأوامر مثل Egrep.
واجهت نفس المشكلة وحلها ربما ليس أفضل طريقة ولكنها تعمل. لقد استبدلت كل فترات استراحة الخط قبل أن أقوم بمطابقتي الحقيقية:
mystring= Regex.Replace(mystring, "\r\n", "")
أنا أتعامل مع HTML ، لذا فإن استراحات الخط لا تهمني حقًا في هذه الحالة.
لقد جربت كل الاقتراحات أعلاه بدون حظ ، أنا أستخدم .NET 3.5 FYI
في JavaScript ، يمكنك استخدام [^]* للبحث عن صفر لأحرف لا حصر لها ، بما في ذلك فواصل الخط.
$("#find_and_replace").click(function() {
var text = $("#textarea").val();
search_term = new RegExp("[^]*<Foobar>", "gi");;
replace_term = "Replacement term";
var new_text = text.replace(search_term, replace_term);
$("#textarea").val(new_text);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="find_and_replace">Find and replace</button>
<br>
<textarea ID="textarea">abcde
fghij<Foobar></textarea>
عموما . لا يتطابق مع الخطوط الجديدة ، لذا حاول ((.|\n)*)<foobar>
أردت أن أتطابق مع مجموعة خاصة إذا كانت كتلة في جافا
...
...
if(isTrue){
doAction();
}
...
...
}
إذا استخدمت regexp
if \(isTrue(.|\n)*}
وشملت الدعامة الإغلاق لكتلة الطريقة لذلك استخدمت
if \(!isTrue([^}.]|\n)*}
لاستبعاد الدعامة الختامية من مباراة Wildcard.
غالبًا ما يتعين علينا تعديل فرعية مع بعض الكلمات الرئيسية المنتشرة عبر الخطوط التي تسبق السلسلة الفرعية. النظر في عنصر XML:
<TASK>
<UID>21</UID>
<Name>Architectural design</Name>
<PercentComplete>81</PercentComplete>
</TASK>
لنفترض أننا نريد تعديل 81 ، لبعض القيمة الأخرى ، قل 40. حدد أولاً .UID.21..UID.
, ثم تخطي جميع الشخصيات بما في ذلك \n
حتى .PercentCompleted.
. نمط التعبير العادي ومواصفات الاستبدال هي:
String hw = new String("<TASK>\n <UID>21</UID>\n <Name>Architectural design</Name>\n <PercentComplete>81</PercentComplete>\n</TASK>");
String pattern = new String ("(<UID>21</UID>)((.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
String replaceSpec = new String ("$1$2$440$6");
//note that the group (<PercentComplete>) is $4 and the group ((.|\n)*?) is $2.
String iw = hw.replaceFirst(pattern, replaceSpec);
System.out.println(iw);
<TASK>
<UID>21</UID>
<Name>Architectural design</Name>
<PercentComplete>40</PercentComplete>
</TASK>
المجموعة الفرعية (.|\n)
ربما المجموعة المفقودة $3
. إذا نجحنا في عدم التغلب عليها (?:.|\n)
ثم $3
هو (<PercentComplete>)
. لذلك النمط و replaceSpec
يمكن أن يكون أيضًا:
pattern = new String("(<UID>21</UID>)((?:.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
replaceSpec = new String("$1$2$340$5")
ويعمل الاستبدال بشكل صحيح كما كان من قبل.