4
$\begingroup$

This question already has an answer here:

How can I find all the (non-overlapping) substrings that start with a specific string of characters (e.g. ">>") and end with another specified string (e.g. "<<"?

For example, when I try the following,

StringCases["ccc>>ccccccc<<cccccc>>cccccccccccccc<<ccccc",">>" ~~ __ ~~ "<<"] 

I get,

{">>ccccccc<<cccccc>>cccccccccccccc<<"}

but I want

{">>ccccccc<<", ">>cccccccccccccc<<"}.

Furthermore, how do I add a pattern that chooses strings smaller than 10 characters?

{">>ccccccc<<"}
$\endgroup$

marked as duplicate by C. E., m_goldberg, Alexey Popkov, Kuba Aug 8 '17 at 7:10

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 4
    $\begingroup$ See Shortest. StringCases["ccc>>ccccccc<<cccccc>>ccccccc<<ccccc", ">>" ~~ Shortest[__] ~~ "<<"] $\endgroup$ – Jason B. Aug 8 '17 at 1:57
  • $\begingroup$ That works. Thanks. $\endgroup$ – Miladiouss Aug 8 '17 at 1:59
  • 2
    $\begingroup$ Regex: StringCases["ccc>>ccccccc<<cccccc>>cccccccccccccc<<ccccc", RegularExpression[">>(.{1,9})<<"]] $\endgroup$ – J. M. will be back soon Aug 8 '17 at 2:49
  • 1
    $\begingroup$ How can I learn more about string patterns. I usually enjoy reading the Mathemacia documentations, but their string pattern tutorial is not very engaging and informative. Any recomendations? $\endgroup$ – Miladiouss Aug 9 '17 at 8:56
  • $\begingroup$ @mpourrah String patterns are converted into regular expressions and then passed to the PCRE library. Hence in order to understand how they work it is worth to learn regexes. There are great resources on the web for this, for example rexegg.com. For testing how string patterns are converted into regexes there is StringPattern`PatternConvert. $\endgroup$ – Alexey Popkov Aug 10 '17 at 1:53
2
$\begingroup$

If you are guaranteed that all the opening ">>" and closing "<<" tags are exactly balanced without nesting, then the solutions suggested in the comments will give you the shortest substring between the tags:

StringCases["ccc>>ccccccc<<cccccc>>ccccccc<<ccccc", ">>" ~~ Shortest[___] ~~ "<<"]
{">>ccccccc<<", ">>ccccccc<<"}

(I assume that you wish to obtain all the substrings between the tags including zero-length substrings. If you don't want the latter, replace ___ with __ in the string patterns and * with + in the regexes.)

But in a case of non-balanced or nested tags they will fail to give you the shortest substring between the tags:

StringCases["c>>cc>>ccccccc<<cccccc>>ccccccc<<ccccc", ">>" ~~ Shortest[___] ~~ "<<"]
{">>cc>>ccccccc<<", ">>ccccccc<<"}

In such a situation you can use one of the solutions suggested here:

StringCases["c>>cc>>ccccccc<<cccccc>>ccccccc<<ccccc", 
 ">>" ~~ RegularExpression["(?:(?!>>).)*?"] ~~ "<<"]
{">>ccccccc<<", ">>ccccccc<<"}

If you need only substrings with length smaller than 10 characters you can use either the two-argument form of Repeated or the corresponding regex statement:

(* well-balanced tags without nesting *)
StringCases["ccc>>ccccccc<<cccccc>>ccccccc<<ccccc", 
 ">>" ~~ Shortest[Repeated[_, {0, 9}]] ~~ "<<"]
{">>ccccccc<<", ">>ccccccc<<"}
(* non-balanced or nested tags *)
StringCases["c>>cc>>ccccccc<<cccccc>>ccccccc<<ccccc", 
 ">>" ~~ RegularExpression["(?:(?!>>).){0,9}?"] ~~ "<<"]
{">>ccccccc<<", ">>ccccccc<<"}
$\endgroup$
  • $\begingroup$ When we process this string "xx >>aa >>bbb<< >>bbb<< aa<< yy>>>>dfa<<a<<", actually the following result is expected.But the MMA seem don't support the balance group syntax. $\endgroup$ – yode Aug 8 '17 at 6:18
  • $\begingroup$ @yode You are asking for the longest substring between balanced tags, this case is addressed here. As I understand, the OP wants the shortest substring. $\endgroup$ – Alexey Popkov Aug 8 '17 at 6:37
  • $\begingroup$ Ok,I fixed it in the new edit. $\endgroup$ – yode Aug 8 '17 at 7:32
1
$\begingroup$

For the non-balanced or nested tags,we can use ?P

StringCases["xx >>aa >>bbb<< >>bbb<< aa<< yy>>>>dfa<<a<<", 
 RegularExpression["(?P<a>>>([^<>]|(?P>a))*<<)"]]

{">>aa >>bbb<< >>bbb<< aa<<", ">>>>dfa<<a<<"}

Or ?R

StringCases["xx >>aa >>bbb<< >>bbb<< aa<< yy>>>>dfa<<a<<", 
 RegularExpression[">>[^<>]*((?R)|[^<>])*<<"]]

will give a same result.

For the shortest substring we have more easy solution

StringCases["xx >>aa >>bbb<< >>bbb<< aa<< yy>>>>dfa<<a<<", 
 RegularExpression[">>.+?<<"]]

{">>aa >>bbb<<", ">>bbb<<", ">>>>dfa<<"}

$\endgroup$
  • $\begingroup$ It is a good habit to provide a link to the original answer from where the solution comes. Also it is worth to point out that this solution will give the longest substring between balanced tags (i.e. with nested balanced tags) as opposed to my answer which gives the shortest substring between the tags. $\endgroup$ – Alexey Popkov Aug 8 '17 at 6:46
  • $\begingroup$ Sorry,I just forget the original post,that hard for me to find those link,I alway confusing you and Cuba how to find it so quick.Actually it is from my personal notes.. $\endgroup$ – yode Aug 8 '17 at 6:57
  • $\begingroup$ "how to find it so quick": in my personal notes I always include a link to the post from where I learned the technique. Without such a link it is difficult to understand the idea if I forgotten how the code works. $\endgroup$ – Alexey Popkov Aug 8 '17 at 7:03
  • $\begingroup$ @AlexeyPopkov If I have a misunderstand the OP.Do you think I should delete this answer?Actually that post don't include the method based on ?R.. $\endgroup$ – yode Aug 8 '17 at 7:06
  • $\begingroup$ Since the question is formulated in a confusing way (with insufficient information), your answer is appropriate. You shouldn't delete it. $\endgroup$ – Alexey Popkov Aug 8 '17 at 7:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.