Regular expression to match a #

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Machin

    #16
    Re: Regular expression to match a #

    John Machin wrote:[color=blue]
    > Devan L wrote:
    >[color=green]
    >> John Machin wrote:
    >>[color=darkred]
    >>> Aahz wrote:
    >>>
    >>>> In article <42fb45d7$1@new s.eftel.com>,
    >>>> John Machin <sjmachin@lexic on.net> wrote:
    >>>>
    >>>>
    >>>>> Search for r'^something' can never be better/faster than match for
    >>>>> r'something', and with a dopey implementation of search [which
    >>>>> Python's
    >>>>> re is NOT] it could be much worse. So please don't tell newbies to
    >>>>> search for r'^something'.
    >>>>
    >>>>
    >>>>
    >>>> You're somehow getting mixed up in thinking that "^" is some kind of
    >>>> "not" operator -- it's the start of line anchor in this context.
    >>>
    >>>
    >>> I can't imagine where you got that idea from.
    >>>
    >>> If I change "[which Python's re is NOT]" to "[Python's re's search() is
    >>> not dopey]", does that help you?
    >>>
    >>> The point was made in a context where the OP appeared to be reading a
    >>> line at a time and parsing it, and re.compile(r'so mething').match ()
    >>> would do the job; re.compile(r'^s omething').sear ch() will do the job too
    >>> -- BECAUSE ^ means start of line anchor -- but somewhat redundantly, and
    >>> very inefficiently in the failing case with dopey implementations of
    >>> search() (which apply match() at offsets 0, 1, 2, .....).[/color]
    >>
    >>
    >>
    >> I don't see much difference.[/color]
    >
    >
    > and I didn't expect that you would -- like I wrote above: "Python's re's
    > search() is not dopey".[/color]

    *ahem*

    C:\junk>python
    Python 2.4.1 (#65, Mar 30 2005, 09:13:57) [MSC v.1310 32 bit (Intel)] on
    win32
    Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
    >>> import timeit
    >>> t1 = timeit.Timer('r e.search("^\w", " will not work")','import re')
    >>> t2 = timeit.Timer('r e.match("\w"," will not work")','import re')
    >>> t3 = timeit.Timer('o bj(" will not work")','import[/color][/color][/color]
    re;obj=re.compi le("^\w").s
    earch')[color=blue][color=green][color=darkred]
    >>> t4 = timeit.Timer('o bj(" will not work")','import[/color][/color][/color]
    re;obj=re.compi le("\w").ma
    tch')[color=blue][color=green][color=darkred]
    >>> t5 = timeit.Timer('o bj(" will not work[/color][/color][/color]
    qqqqqqqqqqqqqqq qqqqqqqqqqqqqqq qqqq")'
    ,'import re;obj=re.compi le("^\w").searc h')[color=blue][color=green][color=darkred]
    >>> t6 = timeit.Timer('o bj(" will not work[/color][/color][/color]
    qqqqqqqqqqqqqqq qqqqqqqqqqqqqqq qqqq")'
    ,'import re;obj=re.compi le("\w").match' )[color=blue][color=green][color=darkred]
    >>> ["%.3f" % t.timeit() for t in t1, t2, t3, t4][/color][/color][/color]
    ['5.510', '4.835', '1.588', '1.178'][color=blue][color=green][color=darkred]
    >>> ["%.3f" % t.timeit() for t in t1, t2, t3, t4][/color][/color][/color]
    ['5.512', '4.808', '1.584', '1.170']

    Observation: factoring out the compile step makes the difference much
    more apparent.
    [color=blue][color=green][color=darkred]
    >>> ["%.3f" % t.timeit() for t in t3, t4, t5, t6][/color][/color][/color]
    ['1.578', '1.175', '2.283', '1.174'][color=blue][color=green][color=darkred]
    >>> ["%.3f" % t.timeit() for t in t3, t4, t5, t6][/color][/color][/color]
    ['1.582', '1.179', '2.284', '1.172'][color=blue][color=green][color=darkred]
    >>>[/color][/color][/color]

    Conclusion: search time depends on length of searched string.

    Meta-conclusion: Either I have to retract my
    based-on-hope-rather-than-on-experimentation assertion, or redefine "not
    dopey" to mean "surely nobody would search for ^x when match x would do,
    so it would be dopey to optimise re for that" :-)

    So, back to the original point:

    If re.match("somet hing") does the job you want, don't use
    re.search("^som ething") instead.

    Comment

    • John Machin

      #17
      Re: Regular expression to match a #

      Devan L wrote:[color=blue]
      > John Machin wrote:
      >[color=green]
      >>Devan L wrote:
      >>[color=darkred]
      >>>John Machin wrote:
      >>>
      >>>
      >>>>Aahz wrote:
      >>>>
      >>>>
      >>>>>In article <42fb45d7$1@new s.eftel.com>,
      >>>>>John Machin <sjmachin@lexic on.net> wrote:
      >>>>>
      >>>>>
      >>>>>
      >>>>>>Search for r'^something' can never be better/faster than match for
      >>>>>>r'somethi ng', and with a dopey implementation of search [which Python's
      >>>>>>re is NOT] it could be much worse. So please don't tell newbies to
      >>>>>>search for r'^something'.
      >>>>>
      >>>>>
      >>>>>You're somehow getting mixed up in thinking that "^" is some kind of
      >>>>>"not" operator -- it's the start of line anchor in this context.
      >>>>
      >>>>I can't imagine where you got that idea from.
      >>>>
      >>>>If I change "[which Python's re is NOT]" to "[Python's re's search() is
      >>>>not dopey]", does that help you?
      >>>>
      >>>>The point was made in a context where the OP appeared to be reading a
      >>>>line at a time and parsing it, and re.compile(r'so mething').match ()
      >>>>would do the job; re.compile(r'^s omething').sear ch() will do the job too
      >>>>-- BECAUSE ^ means start of line anchor -- but somewhat redundantly, and
      >>>>very inefficiently in the failing case with dopey implementations of
      >>>>search() (which apply match() at offsets 0, 1, 2, .....).
      >>>
      >>>
      >>>I don't see much difference.[/color]
      >>
      >>and I didn't expect that you would -- like I wrote above: "Python's re's
      >>search() is not dopey".[/color]
      >
      >
      > Your wording makes it hard to distinguish what exactly is "dopey".
      >[/color]

      """
      dopey implementations of search() (which apply match() at offsets 0, 1,
      2, .....).
      """

      The "dopiness" is that the ^ operator means that the pattern cannot
      possibly match starting at 1, 2, 3, etc but a non-optimised search will
      not recognise that and will try all possibilities, so the failing case
      takes time dependant on the length of the string.

      Comment

      • Bryan Olson

        #18
        Re: Regular expression to match a #

        John Machin wrote:
        [...][color=blue]
        > Observation: factoring out the compile step makes the difference much
        > more apparent.
        >[color=green][color=darkred]
        > >>> ["%.3f" % t.timeit() for t in t3, t4, t5, t6][/color][/color]
        > ['1.578', '1.175', '2.283', '1.174'][color=green][color=darkred]
        > >>> ["%.3f" % t.timeit() for t in t3, t4, t5, t6][/color][/color]
        > ['1.582', '1.179', '2.284', '1.172'][color=green][color=darkred]
        > >>>[/color][/color][/color]

        To make it even more apparent, try:

        import re
        import profile

        startsz = re.compile('^z' )

        for s in ('x' * 1000, 'x' * 100000, 'x'*10000000):
        profile.run('st artsz.search(s) ')

        Profile report is below.

        [color=blue]
        > Conclusion: search time depends on length of searched string.
        >
        > Meta-conclusion: Either I have to retract my
        > based-on-hope-rather-than-on-experimentation assertion, or redefine "not
        > dopey" to mean "surely nobody would search for ^x when match x would do,
        > so it would be dopey to optimise re for that" :-)[/color]

        No question, there's some dopiness to searching for the
        beginning of the string at places other than beginning of the
        string.

        The tricky part would be optimizing '$'.


        --
        --Bryan


        4 function calls in 0.003 CPU seconds

        Ordered by: standard name

        ncalls tottime percall cumtime percall filename:lineno (function)
        1 0.000 0.000 0.000 0.000 :0(search)
        1 0.003 0.003 0.003 0.003 :0(setprofile)
        1 0.000 0.000 0.000 0.000 <string>:1(?)
        0 0.000 0.000 profile:0(profi ler)
        1 0.000 0.000 0.003 0.003 profile:0(start sz.search(s))


        4 function calls in 0.002 CPU seconds

        Ordered by: standard name

        ncalls tottime percall cumtime percall filename:lineno (function)
        1 0.002 0.002 0.002 0.002 :0(search)
        1 0.000 0.000 0.000 0.000 :0(setprofile)
        1 0.000 0.000 0.002 0.002 <string>:1(?)
        0 0.000 0.000 profile:0(profi ler)
        1 0.000 0.000 0.002 0.002 profile:0(start sz.search(s))


        4 function calls in 0.228 CPU seconds

        Ordered by: standard name

        ncalls tottime percall cumtime percall filename:lineno (function)
        1 0.228 0.228 0.228 0.228 :0(search)
        1 0.000 0.000 0.000 0.000 :0(setprofile)
        1 0.000 0.000 0.228 0.228 <string>:1(?)
        0 0.000 0.000 profile:0(profi ler)
        1 0.000 0.000 0.228 0.228 profile:0(start sz.search(s))

        Comment

        • Duncan Booth

          #19
          Re: Regular expression to match a #

          John Machin wrote:
          [color=blue]
          > The point was made in a context where the OP appeared to be reading a
          > line at a time and parsing it, and re.compile(r'so mething').match ()
          > would do the job; re.compile(r'^s omething').sear ch() will do the job too
          > -- BECAUSE ^ means start of line anchor -- but somewhat redundantly, and
          > very inefficiently in the failing case with dopey implementations of
          > search() (which apply match() at offsets 0, 1, 2, .....).[/color]

          Answering the question you think should have been asked rather than the
          question which was actually asked is a great newsnet tradition, and often
          more helpful to the poster than a straight answer would have been. However,
          you do have to be careful to make it clear that is what you are doing.

          The OP did not use the word 'line' once in his post. He simply said he was
          searching a string. You didn't use the word 'line' either. If you are going
          to read more into the question than was actually asked, please try to say
          what question it is you are actually answering.

          If he is using individual lines and re.match then the presence or absence
          of a leading ^ makes virtually no difference. If he is looking for all
          occurences in a multiline string then re.search with an anchored match is a
          correct way to do it (splitting the string into lines and using re.match is
          an alternative which may or may not be appropriate).

          Either way, putting the focus on the ^ was inappropriate: the issue is
          whether to use re.search or re.match. If you assume that the search fails
          on an 80 character line, then I get timings of 6.48uS (re.search), 4.68uS
          (re.match with ^), 4.66uS (re.match without ^). A failing search on a
          10,000 character line shows how performance will degrade (225uS for search,
          no change for match), but notice that searching 1 10,000 character string
          is more than twice as fast as matching 125 80 character lines.

          I don't understand what you think an implementation of search() can do in
          this case apart from trying for a match at offsets 0, 1, 2, ...? It could
          find a match at any starting offset within the string, so it must scan the
          string in some form. A clever regex implementation will use Boyer-Moore
          where it can to avoid checking every index in the string, but for the
          pattern I suggested it would suprise me if any implementations actually
          manage much of an optimisation.

          Comment

          • Duncan Booth

            #20
            Re: Regular expression to match a #

            John Machin wrote:
            [color=blue][color=green]
            >> Your wording makes it hard to distinguish what exactly is "dopey".
            >>[/color]
            >
            > """
            > dopey implementations of search() (which apply match() at offsets 0, 1,
            > 2, .....).
            > """
            >
            > The "dopiness" is that the ^ operator means that the pattern cannot
            > possibly match starting at 1, 2, 3, etc but a non-optimised search will
            > not recognise that and will try all possibilities, so the failing case
            > takes time dependant on the length of the string.[/color]

            The ^ operator can match at any position in the string if the preceding
            character was a newline. 'Dopey' would be failing to take this into
            account.

            Comment

            Working...