Regex: для извлечения подстроки между двумя тегами в строке

У меня есть файл в следующем формате:

Данные Данные
Данные
[Начать]
Данные, которые я хочу
[Конец]
Данные

Я хотел бы захватить Data I wantмежду [Start][End]тегами и с помощью Regex. Может ли кто-нибудь показать мне, как это можно сделать?

9 ответов

  1. \[start\]\s*(((?!\[start\]|\[end\]).)+)\s*\[end\]
    

    Это, надеюсь, падение [start]и [end]маркеры, а также.

  2. С Perl вы можете окружить данные, которые вы хотите с ()’S и вытащить его позже, возможно, другие языки имеют аналогичную функцию.

    if ($s_output =~ /(data data data data START(data data data)END (data data)/) 
    {
        $dataAllOfIt = 
    	
    \[start\]\s*(((?!\[start\]|\[end\]).)+)\s*\[end\]
    

    This should hopefully drop the [start] and [end] markers as well.

    \[start\](.*?)\[end\]
    

    Zhich'll put the text in the middle within a capture.

    $text ="Data Data Data start Data i want end Data";
    ($content) = $text =~ m/ start (.*) end /;
    print $content;
    

    I had a similar problem for a while & I can tell you this method works...

    A more complete discussion of the pitfalls of using a regex to find matching tags can be found at: http://faq.perl.org/perlfaq4.html#How_do_I_find_matchi. In particular, be aware that nesting tags really need a full-fledged parser in order to be interpreted correctly.

    Note that case sensitivity will need to be turned off in order to answer the question as stated. In perl, that's the i modifier:

    $ echo "Data Data Data [Start] Data i want [End] Data" \
      | perl -ne '/\[start\](.*?)\[end\]/i; print "$1\n"'
     Data i want 
    

    The other trick is to use the *? quantifier which turns off the greediness of the captured match. For instance, if you have a non-matching [end] tag:

    Data Data [Start] Data i want [End] Data [end]
    

    you probably don't want to capture:

     Data i want [End] Data
    

    While you can use a regular expression to parse the data between opening and closing tags, you need to think long and hard as to whether this is a path you want to go down. The reason for it is the potential of tags to nest: if nesting tags could ever happen or may ever happen, the language is said to no longer be regular, and regular expressions cease to be the proper tool for parsing it.

    Many regular expression implementations, such as PCRE or perl's regular expressions, support backtracking which can be used to achieve this rough effect. But PCRE (unlike perl) doesn't support unlimited backtracking, and this can actually cause things to break in weird ways as soon as you have too many tags.

    There's a very commonly cited blog post that discusses this more, http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html (google for it and check the cache currently, they seem to be having some downtime)

    Well, if you guarantee that each start tag is followed by an end tag then the following would work.

    \[start\](.*?)\[end\]
    

    However, If you have complex text such as the follwoing:

    [start] sometext [start] sometext2 [end] sometext [end]
    

    then you would run into problems with regex.

    Now the following example will pull out all the hot links in a page:

    '/<a(.*?)a>/i'
    

    In the above case we can guarantee that there would not be any nested cases of:

    '<a></a>'
    

    So, this is a complex question and can't just be solved with a simple answer.

    With Perl you can surround the data you want with ()'s and pull it out later, perhaps other languages have a similar feature.

    if ($s_output =~ /(data data data data START(data data data)END (data data)/) 
    {
        $dataAllOfIt = $1;      # 1 full string
        $dataInMiddle = $2;     # 2 Middle Data
        $dataAtEnd = $3;        # 3 End Data
    }
    

    Refer to this question to pull out text between tags with space characters and dots (.)

    [\S\s] is the one I used

    Regex to match any character including new lines

    Reading the text with in the square brackets [] i.e.[Start] and [End] and validate the array with a list of values. jsfiddle http://jsfiddle.net/muralinarisetty/r4s4wxj4/1/

    var mergeFields = ["[sitename]",
                       "[daystoholdquote]",
                       "[expires]",
                       "[firstname]",
                       "[lastname]",
                       "[sitephonenumber]",
                       "[hoh_firstname]",
                       "[hoh_lastname]"];       
    
    var str = "fee [sitename] [firstname] \
    sdfasd [lastname] ";
    var res = validateMeargeFileds(str);
    console.log(res);
    
    function validateMeargeFileds(input) {
        var re = /\[\w+]/ig;
        var isValid;
        var myArray = input.match(re);
    
        try{
            if (myArray.length > 0) {
                myArray.forEach(function (field) {
    
                    isValid = isMergeField(field);
    
                    if (!isValid){
                       throw e;                        
                    }
                });
            }
        }
        catch(e) {        
        }
    
        return isValid;
    }
    
    function isMergeField(mergefield) {
        return mergeFields.indexOf(mergefield.toLowerCase()) > -1;
    }
    

    ; # 1 full string
    $dataInMiddle = ; # 2 Middle Data
    $dataAtEnd = ; # 3 End Data
    }

  3. Более полное обсуждение подводных камней использования regex для поиска совпадающих тегов можно найти по адресу: http://faq.perl.org/perlfaq4.html#How_do_I_find_matchi . В частности, имейте в виду, что для правильной интерпретации вложенных тегов действительно нужен полноценный парсер.

    Обратите внимание, что для ответа на заданный вопрос чувствительность к регистру необходимо отключить. В perl это модификатор i:

    $ echo "Data Data Data [Start] Data i want [End] Data" \
      | perl -ne '/\[start\](.*?)\[end\]/i; print "
    	
    \[start\]\s*(((?!\[start\]|\[end\]).)+)\s*\[end\]
    

    This should hopefully drop the [start] and [end] markers as well.

    \[start\](.*?)\[end\]
    

    Zhich'll put the text in the middle within a capture.

    $text ="Data Data Data start Data i want end Data";
    ($content) = $text =~ m/ start (.*) end /;
    print $content;
    

    I had a similar problem for a while & I can tell you this method works...

    A more complete discussion of the pitfalls of using a regex to find matching tags can be found at: http://faq.perl.org/perlfaq4.html#How_do_I_find_matchi. In particular, be aware that nesting tags really need a full-fledged parser in order to be interpreted correctly.

    Note that case sensitivity will need to be turned off in order to answer the question as stated. In perl, that's the i modifier:

    $ echo "Data Data Data [Start] Data i want [End] Data" \
      | perl -ne '/\[start\](.*?)\[end\]/i; print "$1\n"'
     Data i want 
    

    The other trick is to use the *? quantifier which turns off the greediness of the captured match. For instance, if you have a non-matching [end] tag:

    Data Data [Start] Data i want [End] Data [end]
    

    you probably don't want to capture:

     Data i want [End] Data
    

    While you can use a regular expression to parse the data between opening and closing tags, you need to think long and hard as to whether this is a path you want to go down. The reason for it is the potential of tags to nest: if nesting tags could ever happen or may ever happen, the language is said to no longer be regular, and regular expressions cease to be the proper tool for parsing it.

    Many regular expression implementations, such as PCRE or perl's regular expressions, support backtracking which can be used to achieve this rough effect. But PCRE (unlike perl) doesn't support unlimited backtracking, and this can actually cause things to break in weird ways as soon as you have too many tags.

    There's a very commonly cited blog post that discusses this more, http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html (google for it and check the cache currently, they seem to be having some downtime)

    Well, if you guarantee that each start tag is followed by an end tag then the following would work.

    \[start\](.*?)\[end\]
    

    However, If you have complex text such as the follwoing:

    [start] sometext [start] sometext2 [end] sometext [end]
    

    then you would run into problems with regex.

    Now the following example will pull out all the hot links in a page:

    '/<a(.*?)a>/i'
    

    In the above case we can guarantee that there would not be any nested cases of:

    '<a></a>'
    

    So, this is a complex question and can't just be solved with a simple answer.

    With Perl you can surround the data you want with ()'s and pull it out later, perhaps other languages have a similar feature.

    if ($s_output =~ /(data data data data START(data data data)END (data data)/) 
    {
        $dataAllOfIt = $1;      # 1 full string
        $dataInMiddle = $2;     # 2 Middle Data
        $dataAtEnd = $3;        # 3 End Data
    }
    

    Refer to this question to pull out text between tags with space characters and dots (.)

    [\S\s] is the one I used

    Regex to match any character including new lines

    Reading the text with in the square brackets [] i.e.[Start] and [End] and validate the array with a list of values. jsfiddle http://jsfiddle.net/muralinarisetty/r4s4wxj4/1/

    var mergeFields = ["[sitename]",
                       "[daystoholdquote]",
                       "[expires]",
                       "[firstname]",
                       "[lastname]",
                       "[sitephonenumber]",
                       "[hoh_firstname]",
                       "[hoh_lastname]"];       
    
    var str = "fee [sitename] [firstname] \
    sdfasd [lastname] ";
    var res = validateMeargeFileds(str);
    console.log(res);
    
    function validateMeargeFileds(input) {
        var re = /\[\w+]/ig;
        var isValid;
        var myArray = input.match(re);
    
        try{
            if (myArray.length > 0) {
                myArray.forEach(function (field) {
    
                    isValid = isMergeField(field);
    
                    if (!isValid){
                       throw e;                        
                    }
                });
            }
        }
        catch(e) {        
        }
    
        return isValid;
    }
    
    function isMergeField(mergefield) {
        return mergeFields.indexOf(mergefield.toLowerCase()) > -1;
    }
    

    \n"'
    Data i want

    Другой трюк заключается в использовании *? Квантор, который отключает жадность захваченного матча. Например, если у вас есть несоответствующий тег [end] :

    Data Data [Start] Data i want [End] Data [end]
    

    вы, вероятно, не хотите, чтобы захватить:

     Data i want [End] Data
    
  4. Хотя вы можете использовать регулярное выражение для анализа данных между открывающими и закрывающими тегами, вам нужно долго и упорно думать о том, является ли это путь, который вы хотите пройти. Причина этого заключается в потенциале вложенности тегов: если вложенность тегов может когда-либо произойти или может когда-либо произойти, говорят, что язык больше не является регулярным, и регулярные выражения перестают быть правильным инструментом для его анализа.

    Многие реализации регулярных выражений, такие как регулярные выражения PCRE или perl, поддерживают отслеживание, которое может быть использовано для достижения этого грубого эффекта. Но PCRE (в отличие от perl) не поддерживает неограниченное отступление, и это на самом деле может привести к тому, что вещи сломаются странным образом, как только у вас будет слишком много тегов.

    Есть очень часто цитируемое сообщение в блоге, которое обсуждает это больше, http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html (google для него и проверить кэш в настоящее время, они, кажется, некоторые простоя)

  5. Ну, если вы гарантируете, что каждый начальный тег сопровождается конечным тегом, то следующее будет работать.

    \[start\](.*?)\[end\]
    

    Однако, если у вас есть сложный текст, такой как followwoing:

    [start] sometext [start] sometext2 [end] sometext [end]
    

    тогда вы столкнетесь с проблемами с regex.

    Теперь следующий пример вытащит все горячие ссылки на странице:

    '/<a(.*?)a>/i'
    

    В вышеуказанном случае мы можем гарантировать, что не будет вложенных случаев:

    '<a></a>'
    

    Это сложный вопрос, и его нельзя решить простым ответом.

  6. $text ="Data Data Data start Data i want end Data";
    ($content) = $text =~ m/ start (.*) end /;
    print $content;
    

    У меня была похожая проблема некоторое время, и я могу сказать вам, что этот метод работает.

  7. Чтение текста с помощью квадратных скобок [], т. е.[начало] и [конец], и проверка массива со списком значений. jsfiddle http://jsfiddle.net/muralinarisetty/r4s4wxj4/1/

    var mergeFields = ["[sitename]",
                       "[daystoholdquote]",
                       "[expires]",
                       "[firstname]",
                       "[lastname]",
                       "[sitephonenumber]",
                       "[hoh_firstname]",
                       "[hoh_lastname]"];       
    
    var str = "fee [sitename] [firstname] \
    sdfasd [lastname] ";
    var res = validateMeargeFileds(str);
    console.log(res);
    
    function validateMeargeFileds(input) {
        var re = /\[\w+]/ig;
        var isValid;
        var myArray = input.match(re);
    
        try{
            if (myArray.length > 0) {
                myArray.forEach(function (field) {
    
                    isValid = isMergeField(field);
    
                    if (!isValid){
                       throw e;                        
                    }
                });
            }
        }
        catch(e) {        
        }
    
        return isValid;
    }
    
    function isMergeField(mergefield) {
        return mergeFields.indexOf(mergefield.toLowerCase()) > -1;
    }