From 96b5b4420bbf27071447e00aa9887aa36941ce09 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 10 Apr 2022 21:18:01 -0700 Subject: [PATCH] Add string:escape_pattern() utility function (#2082) * add string:escape_pattern() to dfhack.lua stolen from devel/query.lua. will migrate scripts to use the common implementation later --- docs/Lua API.rst | 45 +++++++++++++++++++++++++++++++++++++++++ docs/changelog.txt | 2 ++ library/lua/dfhack.lua | 6 ++++++ test/library/string.lua | 15 ++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 6b58574de..5c73dbbd0 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -2643,6 +2643,51 @@ environment by the mandatory init file dfhack.lua: Walks a sequence of dereferences, which may be represented by numbers or strings. Returns *nil* if any of obj or indices is *nil*, or a numeric index is out of array bounds. +.. _lua-string: + +String class extentions +----------------------- + +DFHack extends Lua's basic string class to include a number of convenience +functions. These are invoked just like standard string functions, e.g.:: + + if imastring:startswith('imaprefix') then + +* ``string:startswith(prefix)`` + + Returns ``true`` if the first ``#prefix`` characters of the string are equal + to ``prefix``. Note that ``prefix`` is not interpreted as a pattern. + +* ``string:endswith(suffix)`` + + Returns ``true`` if the last ``#suffix`` characters of the string are equal + to ``suffix``. Note that ``suffix`` is not interpreted as a pattern. + +* ``string:split([delimiter[, plain]])`` + + Split a string by the given delimiter. If no delimiter is specified, space + (``' '``) is used. The delimter is treated as a pattern unless a ``plain`` is + specified and set to ``true``. To treat multiple successive delimiter + characters as a single delimiter, e.g. to avoid getting empty string elements, + pass a pattern like ``' +'``. Be aware that passing patterns that match empty + strings (like ``' *'``) will result in improper string splits. + +* ``string:trim()`` + + Removes spaces (i.e. everything that matches ``'%s'``) from the start and end + of a string. Spaces between non-space characters are left untouched. + +* ``string:wrap([width])`` + + Inserts newlines into a string so no individual line exceeds the given width. + Lines are split at space-separated word boundaries. Any existing newlines are + kept in place. If a single word is longer than width, it is split over + multiple lines. If width is not specified, 72 is used. + +* ``string:escape_pattern()`` + + Escapes regex special chars in a string. E.g. ``'a+b'`` -> ``'a%+b'``. + utils ===== diff --git a/docs/changelog.txt b/docs/changelog.txt index d7fcb9617..c4e1fed4e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Updated information regarding obtaining a compatible Windows build environment - `confirm`: Correct the command name in the plugin help text - ``Quickfort Blueprint Editing Guide``: added screenshots to the Dreamfort case study and overall clarified text +- Document DFHack `lua-string` (``startswith``, ``endswith``, ``split``, ``trim``, ``wrap``, and ``escape_pattern``). ## API - Added functions reverse-engineered from ambushing unit code: ``Units::isHidden``, ``Units::isFortControlled``, ``Units::getOuterContainerRef``, ``Items::getOuterContainerRef`` @@ -71,6 +72,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - Lua wrappers for functions reverse-engineered from ambushing unit code: ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` - ``dwarfmode.enterSidebarMode()``: passing ``df.ui_sidebar_mode.DesignateMine`` now always results in you entering ``DesignateMine`` mode and not ``DesignateChopTrees``, even when you looking at the surface where the default designation mode is ``DesignateChopTrees`` +- New string class function: ``string:escape_pattern()`` escapes regex special characters within a string # 0.47.05-r4 diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 11eebcbf7..5fe377b50 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -462,6 +462,12 @@ function string:wrap(width) return table.concat(wrapped_text, '\n') end +-- Escapes regex special chars in a string. E.g. "a+b" -> "a%+b" +local regex_chars_pattern = '(['..('%^$()[].*+-?'):gsub('(.)', '%%%1')..'])' +function string:escape_pattern() + return self:gsub(regex_chars_pattern, '%%%1') +end + -- String conversions function dfhack.persistent:__tostring() diff --git a/test/library/string.lua b/test/library/string.lua index 350f07d5e..d45be4b3f 100644 --- a/test/library/string.lua +++ b/test/library/string.lua @@ -68,3 +68,18 @@ function test.wrap() expect.eq('hel\nloo\nwor\nldo', ('helloo worldo'):wrap(3)) expect.eq('', (''):wrap()) end + +function test.escape_pattern() + -- no change expected + expect.eq('', (''):escape_pattern()) + expect.eq(' ', (' '):escape_pattern()) + expect.eq('abc', ('abc'):escape_pattern()) + expect.eq('a,b', ('a,b'):escape_pattern()) + expect.eq('"a,b"', ('"a,b"'):escape_pattern()) + + -- excape regex chars + expect.eq('iz for me%?', ('iz for me?'):escape_pattern()) + expect.eq('%.%*', ('.*'):escape_pattern()) + expect.eq('%( %) %. %% %+ %- %* %? %[ %] %^ %$', + ('( ) . % + - * ? [ ] ^ $'):escape_pattern()) +end