Source code for PythonExtensionsCollection.String.CString

# **************************************************************************************************************
#
#  Copyright 2020-2022 Robert Bosch GmbH
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
# **************************************************************************************************************
#
# CString.py
#
# XC-CT/ECA3-Queckenstedt
#
# 26.01.2022
#
# **************************************************************************************************************

# -- import standard Python modules
import os, ntpath, re

# **************************************************************************************************************

[docs]class CString(object): """Contains some string computation methods like e.g. normalizing a path.""" # -------------------------------------------------------------------------------------------------------------- #TM***
[docs] def NormalizePath(sPath=None, bWin=False, sReferencePathAbs=None, bConsiderBlanks=False, bExpandEnvVars=True, bMask=True): """ | **Method:** **NormalizePath** Normalizes local paths, paths to local network resources and internet addresses **Args:** **sPath** (*string*) The path to be normalized **bWin** (*boolean; optional; default: False*) If ``True`` then returned path contains masked backslashes as separator, otherwise slashes **sReferencePathAbs** (*string, optional*) In case of ``sPath`` is relative and ``sReferencePathAbs`` (expected to be absolute) is given, then the returned absolute path is a join of both input paths **bConsiderBlanks** (*boolean; optional; default: False*) If ``True`` then the returned path is encapsulated in quotes - in case of the path contains blanks **bExpandEnvVars** (*boolean; optional; default: True*) If ``True`` then in the returned path environment variables are resolved, otherwise not. **bMask** (*boolean; optional; default: True; requires bWin=True*) If ``bWin`` is ``True`` and ``bMask`` is ``True`` then the returned path contains masked backslashes as separator. If ``bWin`` is ``True`` and ``bMask`` is ``False`` then the returned path contains single backslashes only - this might be required for applications, that are not able to handle masked backslashes. In case of ``bWin`` is ``False`` ``bMask`` has no effect. **Returns:** **sPath** (*string*) The normalized path (is ``None`` in case of ``sPath`` is ``None``) | """ if sPath is not None: # -- expand Windows environment variables if bExpandEnvVars is True: sPath = os.path.expandvars(sPath) # - remove leading and trailing horizontal space sPath = sPath.strip(" \t\r\n") # - remove leading and trailing quotes sPath = sPath.strip("\"'") # - remove once more leading and trailing horizontal space # (after the removal of leading and trailing quotes further horizontal space might be there, that has to be removed; # but further levels of nesting are not considered) sPath = sPath.strip(" \t") if sPath == "": return sPath # - remove trailing slash or backslash (maybe at end of path to folder) sPath = sPath.rstrip("/\\") # -------------------------------------------------------------------------------------------------------------- # consider internet addresses and local network resources # -------------------------------------------------------------------------------------------------------------- # -- local network resource / file server # (prepare for Windows explorer) # either (default) # //server.com/abc/xyz # or (with bWin=True); bMask must be False because \\server.com\\abc\\xyz is not allowed # \\server.com\abc\xyz # (=> user is allowed to select bWin but not bMask) # # -- local network resource / file server # (prepare for web browser) # after 'file://///' only single slashes allowed; bWin and bMask must be False # file://///server.com/abc/xyz # (=> user is NOT allowed to select bWin and bMask) # # -- internet address # after server name only single slashes allowed; bWin and bMask must be False # http://server.com/abc/xyz # https://server.com/abc/xyz # (=> user is NOT allowed to select bWin and bMask) # # - not allowed (=> this method must not return this format): # http:\\server.com # https:\\server.com # -------------------------------------------------------------------------------------------------------------- sPathPrefix = None # In case there is any prefix, we remove this prefix, we compute the remaining part of the path separately, # we also modify this prefix manually, and at the end we put the new prefix back to the path. if ( (sPath[:2] == "\\\\") or (sPath[:2] == "//") ): sPath = sPath[2:] if bWin is True: sPathPrefix = "\\\\" else: sPathPrefix = "//" bMask = False # !!! this overrules the input parameter value, because masked backslashes are not allowed in remaining path !!! elif sPath[:10] == "file://///": # exactly this must be given; all other combinations of slashes and backslashes are not handled sPath = sPath[10:] sPathPrefix = "file://///" bWin = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! bMask = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! elif ( (sPath[:7] == "http://") or (sPath[:7] == "http:\\\\") ): sPath = sPath[7:] sPathPrefix = "http://" bWin = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! bMask = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! elif ( (sPath[:8] == "https://") or (sPath[:8] == "https:\\\\") ): sPath = sPath[8:] sPathPrefix = "https://" bWin = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! bMask = False # !!! this overrules the input parameter value, because only single slashes allowed in remaining path !!! else: # Internet addresses and local network resources handled, now checking for relative paths: # In case of sPath is a relative path AND an absolute reference path is provided # merge them to an absolute path; without reference path use standard function to # convert relative path to absolute path if ( (sPath[0] != "%") and (sPath[0] != "$") ): # If sPath starts with '%' or with '$' it is assumed that the path starts with an environment variable (Windows or Linux). # But in this case 'os.path.isabs(sPath)' will not detect this to be an absolute path and will call # 'sPath = os.path.abspath(sPath)' (depending on sReferencePathAbs). This will accidently merge # the root path together with the path starting with the environment variable and cause invalid results. if os.path.isabs(sPath) is False: if sReferencePathAbs is not None: sPath = os.path.join(sReferencePathAbs, sPath) else: sPath = os.path.abspath(sPath) # eof computation of sPathPrefix # - normalize the path (collapse redundant separators and up-level references) # on Windows this converts slashes to backward slashes # sPath = os.path.normpath(sPath) # under Linux this unfortunately keeps redundant separators (in opposite to Windows) # -- alternative sPath = ntpath.normpath(sPath) # - exchange single backslashes by single slashes (= partly we have to repair the outcome of normpath) if bWin is False: sPath = sPath.replace("\\", "/") else: if bMask is True: sPath = sPath.replace("\\", "\\\\") # - restore the path prefix if sPathPrefix is not None: sPath = f"{sPathPrefix}{sPath}" # - consider blanks (prepare path for usage in Windows command line) if bConsiderBlanks is True: if sPath.find(" ") >= 0: sPath = f"\"{sPath}\"" # eof if sPath is not None: return sPath
# eof NormalizePath(sPath=None, bWin=False, sReferencePathAbs=None, bConsiderBlanks=False, bExpandEnvVars=True, bMask=True) # -------------------------------------------------------------------------------------------------------------- #TM***
[docs] def DetectParentPath(sStartPath=None, sFolderName=None, sFileName=None): """ | **Method:** **DetectParentPath** Computes the path to any parent folder inside a given path. Optionally DetectParentPath is able to search for files inside the parent folder. **Args:** **sStartPath** (*string*) The path in which to search for a parent folder **sFolderName** (*string*) The name of the folder to search for within ``sStartPath``. It is possible to provide more than one folder name separated by semicolon **sFileName** (*string, optional*) The name of a file to search within the detected parent folder **Returns:** **sDestPath** (*string*) Path and name of parent folder found inside ``sStartPath``, ``None`` in case of ``sFolderName`` is not found inside ``sStartPath``. In case of more than one parent folder is found ``sDestPath`` contains the first result and ``listDestPaths`` contains all results. **listDestPaths** (*list*) If ``sFolderName`` contains a single folder name this list contains only one element that is ``sDestPath``. In case of ``FolderName`` contains a semicolon separated list of several folder names this list contains all found paths of the given folder names. ``listDestPaths`` is ``None`` (and not an empty list!) in case of ``sFolderName`` is not found inside ``sStartPath``. **sDestFile** (*string*) Path and name of ``sFileName``, in case of ``sFileName`` is given and found inside ``listDestPaths``. In case of more than one file is found ``sDestFile`` contains the first result and ``listDestFiles`` contains all results. ``sDestFile`` is ``None`` in case of ``sFileName`` is ``None`` and also in case of ``sFileName`` is not found inside ``listDestPaths`` (and therefore also in case of ``sFolderName`` is not found inside ``sStartPath``). **listDestFiles** (*list*) Contains all positions of ``sFileName`` found inside ``listDestPaths``. ``listDestFiles`` is ``None`` (and not an empty list!) in case of ``sFileName`` is ``None`` and also in case of ``sFileName`` is not found inside ``listDestPaths`` (and therefore also in case of ``sFolderName`` is not found inside ``sStartPath``). **sDestPathParent** (*string*) The parent folder of ``sDestPath``, ``None`` in case of ``sFolderName`` is not found inside ``sStartPath`` (``sDestPath`` is ``None``). | """ sDestPath = None listDestPaths = None sDestFile = None listDestFiles = None sDestPathParent = None if sStartPath is None: return sDestPath, listDestPaths, sDestFile, listDestFiles, sDestPathParent if sFolderName is None: return sDestPath, listDestPaths, sDestFile, listDestFiles, sDestPathParent sStartPath = sStartPath.strip() if sStartPath == "": return sDestPath, listDestPaths, sDestFile, listDestFiles, sDestPathParent sFolderName = sFolderName.strip() if sFolderName == "": return sDestPath, listDestPaths, sDestFile, listDestFiles, sDestPathParent listSplit = sFolderName.split(';') listTopLevelFolders = [] for sFolder in listSplit: # removing duplicates sFolder = sFolder.strip() if sFolder != "": if sFolder not in listTopLevelFolders: listTopLevelFolders.append(sFolder) # eof for sFolder in listSplit: nNrOfFolders = len(listTopLevelFolders) sStartPath = CString.NormalizePath(sStartPath) listLevels = sStartPath.split("/") listDestPaths = [] while len(listLevels) > 0: # -- merging paths with folder names and search for existing combinations sPathParent = "/".join(listLevels) for sTLFolder in listTopLevelFolders: sSubPath = sPathParent + "/" + sTLFolder if os.path.isdir(sSubPath) is True: listDestPaths.append(sSubPath) if len(listTopLevelFolders) == len(listDestPaths): # all folders found break else: listLevels.pop() # eof while len(listLevels) > 0: sDestPath = None sDestPathParent = None if len(listDestPaths) > 0: # -- returning sDestPath and sDestPathParent related to first entry in list; just to return anything else than None sDestPath = listDestPaths[0] sDestPathParent = CString.NormalizePath(os.path.dirname(sDestPath)) # -- optionally searching also for a single file # Input: file name # Output: full path of file and list of full paths of files (!!! limited to 'listDestPaths' !!!) listDestFiles = [] if ( (sFileName is not None) and (len(listDestPaths) > 0) ): for sDestPathToWalk in listDestPaths: for sLocalRootPath, listFolderNames, listFileNames in os.walk(sDestPathToWalk): for sFileNameTmp in listFileNames: if sFileNameTmp == sFileName: sFile = CString.NormalizePath(os.path.join(sLocalRootPath, sFileName)) listDestFiles.append(sFile) # eof for sLocalRootPath, listFolderNames, listFileNames in os.walk(sDestPathToWalk): # eof for sDestPathToWalk in listDestPaths: # eof if ( (sFileName is not None) and (len(listDestPaths) > 0) ): if len(listDestFiles) > 0: listDestFiles.sort() sDestFile = listDestFiles[0] # just to return anything else than None # -- preparing output (setting empty lists to None, to have unique criteria for results not available) if listDestPaths is not None: if len(listDestPaths) == 0: listDestPaths = None if listDestFiles is not None: if len(listDestFiles) == 0: listDestFiles = None return sDestPath, listDestPaths, sDestFile, listDestFiles, sDestPathParent
# eof def DetectParentPath(sStartPath=None, sFolderName=None, sFileName=None): # -------------------------------------------------------------------------------------------------------------- #TM***
[docs] def StringFilter(sString = None, bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = None, sInclRegEx = None, sExclRegEx = None, bDebug = False): """ | During the computation of strings there might occur the need to get to know if this string fulfils certain criteria or not. Such a criterion can e.g. be that the string contains a certain substring. Also an inverse logic might be required: In this case the criterion is that the string does **not** contain this substring. It might also be required to combine several criteria to a final conclusion if in total the criterion for a string is fulfilled or not. For example: The string must start with the string *prefix* and must also contain either the string *substring1* or the string *substring2* but must also **not** end with the string *suffix*. This method provides a bunch of predefined filters that can be used singly or combined to come to a final conclusion if the string fulfils all criteria or not. The filters are divided into three different types: 1. Filters that are interpreted as raw strings (called 'standard filters'; no wild cards supported) 2. Filters that are interpreted as regular expressions (called 'regular expression based filters'; the syntax of regular expressions has to be considered) 3. Boolean switches (e.g. indicating if also an empty string is accepted or not) The input string might contain leading and trailing blanks and tabs. This kind of horizontal space is removed from the input string before the standard filters start their work (except the regular expression based filters). The regular expression based filters consider the original input string (including the leading and trailing space). The outcome is that in case of the leading and trailing space shall be part of the criterion, the regular expression based filters can be used only. It is possible to decide if the standard filters shall work case sensitive or not. This decision has no effect on the regular expression based filters. The regular expression based filters always work with the original input string that is not modified in any way. Except the regular expression based filters it is possible to provide more than one string for every standard filter (must be a semikolon separated list in this case). A semicolon that shall be part of the search string, has to be masked in this way: ``\;``. This method returns a boolean value that is ``True`` in case of all criteria are fulfilled, and ``False`` in case of some or all of them are not fulfilled. The default value for all filters is ``None`` (except ``bSkipBlankStrings``). In case of a filter value is ``None`` this filter has no influence on the result. In case of all filters are ``None`` (default) the return value is ``True`` (except the string itself is ``None`` or the string is empty and ``bSkipBlankStrings`` is ``True``). In case of the string is ``None``, the return value is ``False``, because nothing concrete can be done with ``None`` strings. Internally every filter has his own individual acknowledge that indicates if the criterion of this filter is fulfilled or not. The meaning of *criterion fulfilled* of a filter is that the filter supports the final return value ``bAck`` of this method with ``True``. The final return value ``bAck`` of this method is a logical join (``AND``) of all individual acknowledges (except ``bSkipBlankStrings`` and ``sComment``; in case of their criteria are **not** fulfilled, immediately ``False`` is returned). Summarized: * Filters are used to define *criteria* * The return value of this method provides the *conclusion* - indicating if all criteria are fulfilled or not *The following filters are available:* **bSkipBlankStrings** * Like already mentioned above leading and trailing spaces are removed from the input string at the beginning * In case of the result is an empty string and ``bSkipBlankStrings`` is ``True``, the method immediately returns ``False`` and all other filters are ignored **sComment** * In case of the input string starts with the string ``sComment``, the method immediately returns ``False`` and all other filters are ignored * Leading blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * The idea behind this decision is: Ignore a string that is commented out **sStartsWith** * The criterion of this filter is fulfilled in case of the input string starts with the string ``sStartsWith`` * Leading blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``OR``) **sEndsWith** * The criterion of this filter is fulfilled in case of the input string ends with the string ``sEndsWith`` * Trailing blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``OR``) **sStartsNotWith** * The criterion of this filter is fulfilled in case of the input string does **not** start with the string ``sStartsNotWith`` * Leading blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``AND``) **sEndsNotWith** * The criterion of this filter is fulfilled in case of the input string does **not** end with the string ``sEndsNotWith`` * Trailing blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``AND``) **sContains** * The criterion of this filter is fulfilled in case of the input string contains the string ``sContains`` at any position * Leading and trailing blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``OR``) **sContainsNot** * The criterion of this filter is fulfilled in case of the input string does **not** contain the string ``sContainsNot`` at any position * Leading and trailing blanks within the input string have no effect * The decision also depends on ``bCaseSensitive`` * More than one string can be provided (semicolon separated; logical join: ``AND``) **sInclRegEx** * *Include* filter based on regular expressions (consider the syntax of regular expressions!) * The criterion of this filter is fulfilled in case of the regular expression ``sInclRegEx`` matches the input string * Leading and trailing blanks within the input string are considered * ``bCaseSensitive`` has no effect * A semicolon separated list of several regular expressions is **not** supported **sExclRegEx** * *Exclude* filter based on regular expressions (consider the syntax of regular expressions!) * The criterion of this filter is fulfilled in case of the regular expression ``sExclRegEx`` does **not** match the input string * Leading and trailing blanks within the input string are considered * ``bCaseSensitive`` has no effect * A semicolon separated list of several regular expressions is **not** supported *Further parameter:* **sString** The input string that has to be investigated. **bCaseSensitive** (*boolean, optional, default*: ``True``) If ``True``, the standard filters work case sensitive, otherwise not. **bDebug** (*boolean, optional, default*: ``False``) If ``True``, additional output is printed to console (e.g. the decision of every single filter), otherwise not. *Examples:* Returns ``True``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = "Sp", sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = "beats", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) Returns ``False``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = "Sp", sEndsWith = None, sStartsNotWith = None, sEndsNotWith = "minute", sContains = "beats", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) Returns ``True``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = "Beats", sInclRegEx = None, sExclRegEx = None) Returns ``True``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = None, sInclRegEx = r"\d{2}", sExclRegEx = None) Returns ``False``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = "Speed", sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = None, sInclRegEx = r"\d{3}", sExclRegEx = None) Returns ``False``: .. code:: bAck = CString.StringFilter(sString = "Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = "Speed", sEndsWith = "minute", sStartsNotWith = "speed", sEndsNotWith = None, sContains = "beats", sContainsNot = None, sInclRegEx = r"\d{2}", sExclRegEx = r"\d{2}") Returns ``False``: .. code:: bAck = CString.StringFilter(sString = " ", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = None, sInclRegEx = None, sExclRegEx = None) Returns ``False``: .. code:: bAck = CString.StringFilter(sString = "# Speed is 25 beats per minute", bCaseSensitive = True, bSkipBlankStrings = True, sComment = "#", sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = "beats", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) Returns ``False``: .. code:: bAck = CString.StringFilter(sString = " Alpha is not beta; and beta is not gamma ", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = " Alpha ", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) Because blanks around search strings (here ``" Alpha "``) are considered, whereas the blanks around the input string are removed before computation. Therefore ``" Alpha "`` cannot be found within the (shortened) input string. This alternative solution returns ``True``: .. code:: bAck = CString.StringFilter(sString = " Alpha is not beta; and beta is not gamma ", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = None, sContainsNot = None, sInclRegEx = r"\s{3}Alpha", sExclRegEx = None) Returns ``True``: .. code:: bAck = CString.StringFilter(sString = "Alpha is not beta; and beta is not gamma", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = "beta; and", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) The meaning of ``"beta; and"`` is: The criterion is fulfilled in case of either ``"beta"`` or ``" and"`` can be found. That's ``True`` in this example - but this has nothing to do with the fact, that also this string ``"beta; and"`` can be found. A semicolon that shall be part of the search, has to be masked! The meaning of ``"beta\; not"`` in the following example is: The criterion is fulfilled in case of ``"beta; not"`` can be found. That's **not** ``True``. Therefore the method returns ``False``: .. code:: bAck = CString.StringFilter(sString = "Alpha is not beta; and beta is not gamma", bCaseSensitive = True, bSkipBlankStrings = True, sComment = None, sStartsWith = None, sEndsWith = None, sStartsNotWith = None, sEndsNotWith = None, sContains = r"beta\; not", sContainsNot = None, sInclRegEx = None, sExclRegEx = None) | """ if sString is None: return False # hard coded here; no separate filter for that decision # The original string 'sString' is used by regular expression filters sInclRegEx and sExclRegEx. # The stripped string 'sStringStripped' is used by all other filters. sStringStripped = sString.strip(" \t\r\n") # -- skipping blank strings or strings commented out; other filters will not be considered any more in this case if bSkipBlankStrings is True: if sStringStripped == "": return False if sComment is not None: if sComment != "": if bCaseSensitive is True: if sStringStripped.startswith(sComment) is True: return False else: if sStringStripped.upper().startswith(sComment.upper()) is True: return False # -- consider further filters # # No filter set (= no criteria defined) => use this string (bAck is True). # # At least one filter set (except sExclRegEx), at least one set filter fits (except sExclRegEx) => use this string. # Filter sExclRegEx is set and fits => skip this string (final veto). # At least one filter does not fit (except sExclRegEx) => skip this string. # # All filters (except sExclRegEx) are include filter (bAck is True in case of all set filters fit, also the 'not' filters) # The filter sExclRegEx is an exclude filter and has final veto right (can revoke the True from other filters). # # All filters (except sInclRegEx and sExclRegEx) are handled as 'raw strings': no wild cards, just strings, considering bCaseSensitive. # The filters sInclRegEx and sExclRegEx are handled as regular expressions; bCaseSensitive is not considered here. # -- filter specific flags (containing the names of the criteria within their names) bStartsWith = None bEndsWith = None bStartsNotWith = None bEndsNotWith = None bContains = None bContainsNot = None bInclRegEx = None bExclRegEx = None # Meaning: # - Flag is None : filter not set => filter has no effect # - Flag is True : filter set => result: use the input string (from this single filter flag point of view) # - Flag is False: filter set => result: do not use the input string (from this single filter flag point of view) # The results of all flags will be merged at the end of this function to one final conclusion to use the input string # (bAck is True) or not (bAck is False). # Logical join between all set filters: AND # substitute for the masked filter separator '\n' (hopefully the input string does not contain this substitute) sSeparatorSubstitute = "#|S#|E#|P#|A#|R#|A#|T#|O#|R#" # -- filter: starts with # > several filter strings possible (separated by semicolon; logical join: OR) if sStartsWith is not None: if sStartsWith != "": sStartsWithModified = sStartsWith.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listStartsWith = [] if sStartsWith.find(";") >= 0: listParts = sStartsWithModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version listStartsWith.append(sPart) else: sStartsWithModified = sStartsWith.replace(r"\;", ";") # convert to unmasked version listStartsWith.append(sStartsWithModified) bStartsWith = False for sStartsWith in listStartsWith: if bCaseSensitive is True: if sStringStripped.startswith(sStartsWith) is True: bStartsWith = True break else: if sStringStripped.upper().startswith(sStartsWith.upper()) is True: bStartsWith = True break # -- filter: ends with # > several filter strings possible (separated by semicolon; logical join: OR) if sEndsWith is not None: if sEndsWith != "": sEndsWithModified = sEndsWith.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listEndsWith = [] if sEndsWith.find(";") >= 0: listParts = sEndsWithModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version listEndsWith.append(sPart) else: sEndsWithModified = sEndsWith.replace(r"\;", ";") # convert to unmasked version listEndsWith.append(sEndsWithModified) bEndsWith = False for sEndsWith in listEndsWith: if bCaseSensitive is True: if sStringStripped.endswith(sEndsWith) is True: bEndsWith = True break else: if sStringStripped.upper().endswith(sEndsWith.upper()) is True: bEndsWith = True break # -- filter: starts not with # > several filter strings possible (separated by semicolon; logical join: AND) if sStartsNotWith is not None: if sStartsNotWith != "": sStartsNotWithModified = sStartsNotWith.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listStartsNotWith = [] if sStartsNotWith.find(";") >= 0: listParts = sStartsNotWithModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version listStartsNotWith.append(sPart) else: sStartsNotWithModified = sStartsNotWith.replace(r"\;", ";") # convert to unmasked version listStartsNotWith.append(sStartsNotWithModified) bStartsNotWith = True for sStartsNotWith in listStartsNotWith: if bCaseSensitive is True: if sStringStripped.startswith(sStartsNotWith) is True: bStartsNotWith = False break else: if sStringStripped.upper().startswith(sStartsNotWith.upper()) is True: bStartsNotWith = False break # -- filter: ends not with # > several filter strings possible (separated by semicolon; logical join: AND) if sEndsNotWith is not None: if sEndsNotWith != "": sEndsNotWithModified = sEndsNotWith.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listEndsNotWith = [] if sEndsNotWith.find(";") >= 0: listParts = sEndsNotWithModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version listEndsNotWith.append(sPart) else: sEndsNotWithModified = sEndsNotWith.replace(r"\;", ";") # convert to unmasked version listEndsNotWith.append(sEndsNotWithModified) bEndsNotWith = True for sEndsNotWith in listEndsNotWith: if bCaseSensitive is True: if sStringStripped.endswith(sEndsNotWith) is True: bEndsNotWith = False break else: if sStringStripped.upper().endswith(sEndsNotWith.upper()) is True: bEndsNotWith = False break # -- filter: contains # > several filter strings possible (separated by semicolon; logical join: OR) if sContains is not None: if sContains != "": sContainsModified = sContains.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listContains = [] if sContainsModified.find(";") >= 0: listParts = sContainsModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version print(f"- Part: '{sPart}'") listContains.append(sPart) else: sContainsModified = sContains.replace(r"\;", ";") # convert to unmasked version listContains.append(sContainsModified) bContains = False for sContains in listContains: if bCaseSensitive is True: if sStringStripped.find(sContains) >= 0: bContains = True break else: if sStringStripped.upper().find(sContains.upper()) >= 0: bContains = True break # -- filter: contains not # > several filter strings possible (separated by semicolon; logical join: AND) if sContainsNot is not None: if sContainsNot != "": sContainsNotModified = sContainsNot.replace(r"\;", sSeparatorSubstitute) # replace the masked separator by a substitute separator listContainsNot = [] if sContainsNot.find(";") >= 0: listParts = sContainsNotModified.split(";") for sPart in listParts: sPart = sPart.replace(sSeparatorSubstitute , ";") # recover the original version listContainsNot.append(sPart) else: sContainsNotModified = sContainsNot.replace(r"\;", ";") # convert to unmasked version listContainsNot.append(sContainsNotModified) bContainsNot = True for sContainsNot in listContainsNot: if bCaseSensitive is True: if sStringStripped.find(sContainsNot) >= 0: bContainsNot = False break else: if sStringStripped.upper().find(sContainsNot.upper()) >= 0: bContainsNot = False break # -- filter: sInclRegEx # > (take care to mask special characters that are part of the syntax of regular expressions!) # > bCaseSensitive not considered here if sInclRegEx is not None: if sInclRegEx != "": bInclRegEx = False if re.search(sInclRegEx, sString) is not None: bInclRegEx = True # -- last filter: sExclRegEx (final veto right) # > (take care to mask special characters that are part of the syntax of regular expressions!) # > bCaseSensitive not considered here if sExclRegEx is not None: if sExclRegEx != "": bExclRegEx = True if re.search(sExclRegEx, sString) is not None: bExclRegEx = False # -- debug info if bDebug is True: print("\n* [sString] : '" + str(sString) + "'\n") print(" -> [bStartsWith] : '" + str(bStartsWith) + "'") print(" -> [bEndsWith] : '" + str(bEndsWith) + "'") print(" -> [bStartsNotWith] : '" + str(bStartsNotWith) + "'") print(" -> [bEndsNotWith] : '" + str(bEndsNotWith) + "'") print(" -> [bContains] : '" + str(bContains) + "'") print(" -> [bContainsNot] : '" + str(bContainsNot) + "'") print(" -> [bInclRegEx] : '" + str(bInclRegEx) + "'") print(" -> [bExclRegEx] : '" + str(bExclRegEx) + "'\n") # -- final conclusion (AND condition between filters) listDecisions = [] listDecisions.append(bStartsWith) listDecisions.append(bEndsWith) listDecisions.append(bStartsNotWith) listDecisions.append(bEndsNotWith) listDecisions.append(bContains) listDecisions.append(bContainsNot) listDecisions.append(bInclRegEx) listDecisions.append(bExclRegEx) bAck = False # initial # -- 1.) no filter set (all None) nCntDecisions = 0 for bDecision in listDecisions: if bDecision is None: nCntDecisions = nCntDecisions + 1 if nCntDecisions == len(listDecisions): bAck = True if bDebug is True: print(" > case [1] - bAck: " + str(bAck)) # -- 2.) final veto from exclude filter if bExclRegEx is False: bAck = False if bDebug is True: print(" > case [2] - bAck: " + str(bAck)) # -- 3.) exclude filter not set; decision only made by other filters (include) if bExclRegEx is None: bAck = True for bDecision in listDecisions: if bDecision is False: bAck = False break if bDebug is True: print(" > case [3] - bAck: " + str(bAck)) # -- 4.) exclude filter is True (only relevant in case of all other filters are not set; otherwise decision only made by other filters (include)) if bExclRegEx is True: if ( (bStartsWith is None) and (bEndsWith is None) and (bStartsNotWith is None) and (bEndsNotWith is None) and (bContains is None) and (bContainsNot is None) and (bInclRegEx is None) ): bAck = True if bDebug is True: print(" > case [4.1] - bAck: " + str(bAck)) else: bAck = True for bDecision in listDecisions: if bDecision is False: bAck = False break if bDebug is True: print(" > case [4.2] - bAck: " + str(bAck)) if bDebug is True: print() return bAck
# eof def StringFilter(...) # -------------------------------------------------------------------------------------------------------------- #TM***
[docs] def FormatResult(sMethod="", bSuccess=True, sResult=""): """ | **Method:** **FormatResult** Formats the result string ``sResult`` depending on ``bSuccess``: * ``bSuccess`` is ``True`` indicates *success* * ``bSuccess`` is ``False`` indicates an *error* * ``bSuccess`` is ``None`` indicates an *exception* Additionally the name of the method that causes the result, can be provided (*optional*). This is useful for debugging. Returns the formatted result string. | """ if sMethod is None: sMethod = str(sMethod) if sResult is None: sResult = str(sResult) if bSuccess is True: if sMethod != "": sResult = f"[{sMethod}] : {sResult}" elif bSuccess is False: sError = "!!! ERROR !!!" if sMethod != "": sResult = f"{sError}\n[{sMethod}] : {sResult}" else: sResult = f"{sError}\n{sResult}" else: sException = "!!! EXCEPTION !!!" if sMethod != "": sResult = f"{sException}\n[{sMethod}] : {sResult}" else: sResult = f"{sException}\n{sResult}" return sResult
# eof def FormatResult(sMethod="", bSuccess=True, sResult=""): # -------------------------------------------------------------------------------------------------------------- #TM*** # - make the methods static NormalizePath = staticmethod(NormalizePath) DetectParentPath = staticmethod(DetectParentPath) StringFilter = staticmethod(StringFilter) FormatResult = staticmethod(FormatResult)
# eof class CString(object): # **************************************************************************************************************