We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Inconsistency between local and remote version of `conan search`
Depending on searching either in remotes or locally we're getting different results for situations where we don't use wildcards.  
Example:
```
$ conan search zlib
There are no packages matching the 'zlib' pattern

$ conan search zlib*
Existing package recipes:

zlib/1.2.8@conan/stable
zlib/1.2.11@conan/stable
```
```
$ conan search zlib -r conan-center
Existing package recipes:

zlib/1.2.8@conan/stable
zlib/1.2.11@conan/stable
zlib/1.2.11@conan/testing
```
Same for combinations such as `zlib/1.2.8`, `zlib/1.2.8@`, `zlib/1.2.8@conan`, `zlib/1.2.8@conan/` except for `zlib/`.

Proposition: make local search act in the same manner as remote search.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conans/search/search.py`
Content:
```
1 import re
2 import os
3 
4 
5 from fnmatch import translate
6 
7 from conans.errors import ConanException, NotFoundException
8 from conans.model.info import ConanInfo
9 from conans.model.ref import PackageReference, ConanFileReference
10 from conans.paths import CONANINFO
11 from conans.util.log import logger
12 from conans.search.query_parse import infix_to_postfix, evaluate_postfix
13 from conans.util.files import list_folder_subdirs, load
14 
15 
16 def filter_outdated(packages_infos, recipe_hash):
17     result = {}
18     for package_id, info in packages_infos.items():
19         try:  # Existing package_info of old package might not have recipe_hash
20             if info["recipe_hash"] != recipe_hash:
21                 result[package_id] = info
22         except KeyError:
23             pass
24     return result
25 
26 
27 def filter_packages(query, package_infos):
28     if query is None:
29         return package_infos
30     try:
31         if "!" in query:
32             raise ConanException("'!' character is not allowed")
33         if " not " in query or query.startswith("not "):
34             raise ConanException("'not' operator is not allowed")
35         postfix = infix_to_postfix(query) if query else []
36         result = {}
37         for package_id, info in package_infos.items():
38             if evaluate_postfix_with_info(postfix, info):
39                 result[package_id] = info
40         return result
41     except Exception as exc:
42         raise ConanException("Invalid package query: %s. %s" % (query, exc))
43 
44 
45 def evaluate_postfix_with_info(postfix, conan_vars_info):
46 
47     # Evaluate conaninfo with the expression
48 
49     def evaluate_info(expression):
50         """Receives an expression like compiler.version="12"
51         Uses conan_vars_info in the closure to evaluate it"""
52         name, value = expression.split("=", 1)
53         value = value.replace("\"", "")
54         return evaluate(name, value, conan_vars_info)
55 
56     return evaluate_postfix(postfix, evaluate_info)
57 
58 
59 def evaluate(prop_name, prop_value, conan_vars_info):
60     """
61     Evaluates a single prop_name, prop_value like "os", "Windows" against conan_vars_info.serialize_min()
62     """
63 
64     def compatible_prop(setting_value, prop_value):
65         return setting_value is None or prop_value == setting_value
66 
67     info_settings = conan_vars_info.get("settings", [])
68     info_options = conan_vars_info.get("options", [])
69 
70     if prop_name in ["os", "compiler", "arch", "build_type"] or prop_name.startswith("compiler."):
71         return compatible_prop(info_settings.get(prop_name, None), prop_value)
72     else:
73         return compatible_prop(info_options.get(prop_name, None), prop_value)
74     return False
75 
76 
77 def search_recipes(paths, pattern=None, ignorecase=True):
78     # Conan references in main storage
79     if pattern:
80         if isinstance(pattern, ConanFileReference):
81             pattern = str(pattern)
82         pattern = translate(pattern)
83         pattern = re.compile(pattern, re.IGNORECASE) if ignorecase else re.compile(pattern)
84 
85     subdirs = list_folder_subdirs(basedir=paths.store, level=4)
86     if not pattern:
87         return sorted([ConanFileReference(*folder.split("/")) for folder in subdirs])
88     else:
89         ret = []
90         for subdir in subdirs:
91             conan_ref = ConanFileReference(*subdir.split("/"))
92             if pattern:
93                 if pattern.match(str(conan_ref)):
94                     ret.append(conan_ref)
95         return sorted(ret)
96 
97 
98 def search_packages(paths, reference, query):
99     """ Return a dict like this:
100 
101             {package_ID: {name: "OpenCV",
102                            version: "2.14",
103                            settings: {os: Windows}}}
104     param conan_ref: ConanFileReference object
105     """
106     infos = _get_local_infos_min(paths, reference)
107     return filter_packages(query, infos)
108 
109 
110 def _get_local_infos_min(paths, reference):
111     result = {}
112     packages_path = paths.packages(reference)
113     subdirs = list_folder_subdirs(packages_path, level=1)
114     for package_id in subdirs:
115         # Read conaninfo
116         try:
117             package_reference = PackageReference(reference, package_id)
118             info_path = os.path.join(paths.package(package_reference,
119                                                    short_paths=None), CONANINFO)
120             if not os.path.exists(info_path):
121                 raise NotFoundException("")
122             conan_info_content = load(info_path)
123             conan_vars_info = ConanInfo.loads(conan_info_content).serialize_min()
124             result[package_id] = conan_vars_info
125 
126         except Exception as exc:
127             logger.error("Package %s has no ConanInfo file" % str(package_reference))
128             if str(exc):
129                 logger.error(str(exc))
130 
131     return result
132
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conans/search/search.py b/conans/search/search.py
--- a/conans/search/search.py
+++ b/conans/search/search.py
@@ -1,7 +1,6 @@
 import re
 import os
 
-
 from fnmatch import translate
 
 from conans.errors import ConanException, NotFoundException
@@ -90,11 +89,27 @@
         for subdir in subdirs:
             conan_ref = ConanFileReference(*subdir.split("/"))
             if pattern:
-                if pattern.match(str(conan_ref)):
+                if _partial_match(pattern, conan_ref):
                     ret.append(conan_ref)
+
         return sorted(ret)
 
 
+def _partial_match(pattern, conan_ref):
+    """
+    Finds if pattern matches any of partial sums of tokens of conan reference
+    """
+    
+    tokens = str(conan_ref).replace('/', ' / ').replace('@', ' @ ').split()
+
+    def partial_sums(iterable):
+        sum = ''
+        for i in iterable:
+            sum += i
+            yield sum
+
+    return any(map(pattern.match, list(partial_sums(tokens))))
+
 def search_packages(paths, reference, query):
     """ Return a dict like this:

{"golden_diff": "diff --git a/conans/search/search.py b/conans/search/search.py\n--- a/conans/search/search.py\n+++ b/conans/search/search.py\n@@ -1,7 +1,6 @@\n import re\n import os\n \n-\n from fnmatch import translate\n \n from conans.errors import ConanException, NotFoundException\n@@ -90,11 +89,27 @@\n         for subdir in subdirs:\n             conan_ref = ConanFileReference(*subdir.split(\"/\"))\n             if pattern:\n-                if pattern.match(str(conan_ref)):\n+                if _partial_match(pattern, conan_ref):\n                     ret.append(conan_ref)\n+\n         return sorted(ret)\n \n \n+def _partial_match(pattern, conan_ref):\n+    \"\"\"\n+    Finds if pattern matches any of partial sums of tokens of conan reference\n+    \"\"\"\n+    \n+    tokens = str(conan_ref).replace('/', ' / ').replace('@', ' @ ').split()\n+\n+    def partial_sums(iterable):\n+        sum = ''\n+        for i in iterable:\n+            sum += i\n+            yield sum\n+\n+    return any(map(pattern.match, list(partial_sums(tokens))))\n+\n def search_packages(paths, reference, query):\n     \"\"\" Return a dict like this:\n", "issue": "Inconsistency between local and remote version of `conan search`\nDepending on searching either in remotes or locally we're getting different results for situations where we don't use wildcards.  \r\nExample:\r\n```\r\n$ conan search zlib\r\nThere are no packages matching the 'zlib' pattern\r\n\r\n$ conan search zlib*\r\nExisting package recipes:\r\n\r\nzlib/1.2.8@conan/stable\r\nzlib/1.2.11@conan/stable\r\n```\r\n```\r\n$ conan search zlib -r conan-center\r\nExisting package recipes:\r\n\r\nzlib/1.2.8@conan/stable\r\nzlib/1.2.11@conan/stable\r\nzlib/1.2.11@conan/testing\r\n```\r\nSame for combinations such as `zlib/1.2.8`, `zlib/1.2.8@`, `zlib/1.2.8@conan`, `zlib/1.2.8@conan/` except for `zlib/`.\r\n\r\nProposition: make local search act in the same manner as remote search.\n", "before_files": [{"content": "import re\nimport os\n\n\nfrom fnmatch import translate\n\nfrom conans.errors import ConanException, NotFoundException\nfrom conans.model.info import ConanInfo\nfrom conans.model.ref import PackageReference, ConanFileReference\nfrom conans.paths import CONANINFO\nfrom conans.util.log import logger\nfrom conans.search.query_parse import infix_to_postfix, evaluate_postfix\nfrom conans.util.files import list_folder_subdirs, load\n\n\ndef filter_outdated(packages_infos, recipe_hash):\n    result = {}\n    for package_id, info in packages_infos.items():\n        try:  # Existing package_info of old package might not have recipe_hash\n            if info[\"recipe_hash\"] != recipe_hash:\n                result[package_id] = info\n        except KeyError:\n            pass\n    return result\n\n\ndef filter_packages(query, package_infos):\n    if query is None:\n        return package_infos\n    try:\n        if \"!\" in query:\n            raise ConanException(\"'!' character is not allowed\")\n        if \" not \" in query or query.startswith(\"not \"):\n            raise ConanException(\"'not' operator is not allowed\")\n        postfix = infix_to_postfix(query) if query else []\n        result = {}\n        for package_id, info in package_infos.items():\n            if evaluate_postfix_with_info(postfix, info):\n                result[package_id] = info\n        return result\n    except Exception as exc:\n        raise ConanException(\"Invalid package query: %s. %s\" % (query, exc))\n\n\ndef evaluate_postfix_with_info(postfix, conan_vars_info):\n\n    # Evaluate conaninfo with the expression\n\n    def evaluate_info(expression):\n        \"\"\"Receives an expression like compiler.version=\"12\"\n        Uses conan_vars_info in the closure to evaluate it\"\"\"\n        name, value = expression.split(\"=\", 1)\n        value = value.replace(\"\\\"\", \"\")\n        return evaluate(name, value, conan_vars_info)\n\n    return evaluate_postfix(postfix, evaluate_info)\n\n\ndef evaluate(prop_name, prop_value, conan_vars_info):\n    \"\"\"\n    Evaluates a single prop_name, prop_value like \"os\", \"Windows\" against conan_vars_info.serialize_min()\n    \"\"\"\n\n    def compatible_prop(setting_value, prop_value):\n        return setting_value is None or prop_value == setting_value\n\n    info_settings = conan_vars_info.get(\"settings\", [])\n    info_options = conan_vars_info.get(\"options\", [])\n\n    if prop_name in [\"os\", \"compiler\", \"arch\", \"build_type\"] or prop_name.startswith(\"compiler.\"):\n        return compatible_prop(info_settings.get(prop_name, None), prop_value)\n    else:\n        return compatible_prop(info_options.get(prop_name, None), prop_value)\n    return False\n\n\ndef search_recipes(paths, pattern=None, ignorecase=True):\n    # Conan references in main storage\n    if pattern:\n        if isinstance(pattern, ConanFileReference):\n            pattern = str(pattern)\n        pattern = translate(pattern)\n        pattern = re.compile(pattern, re.IGNORECASE) if ignorecase else re.compile(pattern)\n\n    subdirs = list_folder_subdirs(basedir=paths.store, level=4)\n    if not pattern:\n        return sorted([ConanFileReference(*folder.split(\"/\")) for folder in subdirs])\n    else:\n        ret = []\n        for subdir in subdirs:\n            conan_ref = ConanFileReference(*subdir.split(\"/\"))\n            if pattern:\n                if pattern.match(str(conan_ref)):\n                    ret.append(conan_ref)\n        return sorted(ret)\n\n\ndef search_packages(paths, reference, query):\n    \"\"\" Return a dict like this:\n\n            {package_ID: {name: \"OpenCV\",\n                           version: \"2.14\",\n                           settings: {os: Windows}}}\n    param conan_ref: ConanFileReference object\n    \"\"\"\n    infos = _get_local_infos_min(paths, reference)\n    return filter_packages(query, infos)\n\n\ndef _get_local_infos_min(paths, reference):\n    result = {}\n    packages_path = paths.packages(reference)\n    subdirs = list_folder_subdirs(packages_path, level=1)\n    for package_id in subdirs:\n        # Read conaninfo\n        try:\n            package_reference = PackageReference(reference, package_id)\n            info_path = os.path.join(paths.package(package_reference,\n                                                   short_paths=None), CONANINFO)\n            if not os.path.exists(info_path):\n                raise NotFoundException(\"\")\n            conan_info_content = load(info_path)\n            conan_vars_info = ConanInfo.loads(conan_info_content).serialize_min()\n            result[package_id] = conan_vars_info\n\n        except Exception as exc:\n            logger.error(\"Package %s has no ConanInfo file\" % str(package_reference))\n            if str(exc):\n                logger.error(str(exc))\n\n    return result\n", "path": "conans/search/search.py"}], "after_files": [{"content": "import re\nimport os\n\nfrom fnmatch import translate\n\nfrom conans.errors import ConanException, NotFoundException\nfrom conans.model.info import ConanInfo\nfrom conans.model.ref import PackageReference, ConanFileReference\nfrom conans.paths import CONANINFO\nfrom conans.util.log import logger\nfrom conans.search.query_parse import infix_to_postfix, evaluate_postfix\nfrom conans.util.files import list_folder_subdirs, load\n\n\ndef filter_outdated(packages_infos, recipe_hash):\n    result = {}\n    for package_id, info in packages_infos.items():\n        try:  # Existing package_info of old package might not have recipe_hash\n            if info[\"recipe_hash\"] != recipe_hash:\n                result[package_id] = info\n        except KeyError:\n            pass\n    return result\n\n\ndef filter_packages(query, package_infos):\n    if query is None:\n        return package_infos\n    try:\n        if \"!\" in query:\n            raise ConanException(\"'!' character is not allowed\")\n        if \" not \" in query or query.startswith(\"not \"):\n            raise ConanException(\"'not' operator is not allowed\")\n        postfix = infix_to_postfix(query) if query else []\n        result = {}\n        for package_id, info in package_infos.items():\n            if evaluate_postfix_with_info(postfix, info):\n                result[package_id] = info\n        return result\n    except Exception as exc:\n        raise ConanException(\"Invalid package query: %s. %s\" % (query, exc))\n\n\ndef evaluate_postfix_with_info(postfix, conan_vars_info):\n\n    # Evaluate conaninfo with the expression\n\n    def evaluate_info(expression):\n        \"\"\"Receives an expression like compiler.version=\"12\"\n        Uses conan_vars_info in the closure to evaluate it\"\"\"\n        name, value = expression.split(\"=\", 1)\n        value = value.replace(\"\\\"\", \"\")\n        return evaluate(name, value, conan_vars_info)\n\n    return evaluate_postfix(postfix, evaluate_info)\n\n\ndef evaluate(prop_name, prop_value, conan_vars_info):\n    \"\"\"\n    Evaluates a single prop_name, prop_value like \"os\", \"Windows\" against conan_vars_info.serialize_min()\n    \"\"\"\n\n    def compatible_prop(setting_value, prop_value):\n        return setting_value is None or prop_value == setting_value\n\n    info_settings = conan_vars_info.get(\"settings\", [])\n    info_options = conan_vars_info.get(\"options\", [])\n\n    if prop_name in [\"os\", \"compiler\", \"arch\", \"build_type\"] or prop_name.startswith(\"compiler.\"):\n        return compatible_prop(info_settings.get(prop_name, None), prop_value)\n    else:\n        return compatible_prop(info_options.get(prop_name, None), prop_value)\n    return False\n\n\ndef search_recipes(paths, pattern=None, ignorecase=True):\n    # Conan references in main storage\n    if pattern:\n        if isinstance(pattern, ConanFileReference):\n            pattern = str(pattern)\n        pattern = translate(pattern)\n        pattern = re.compile(pattern, re.IGNORECASE) if ignorecase else re.compile(pattern)\n\n    subdirs = list_folder_subdirs(basedir=paths.store, level=4)\n    if not pattern:\n        return sorted([ConanFileReference(*folder.split(\"/\")) for folder in subdirs])\n    else:\n        ret = []\n        for subdir in subdirs:\n            conan_ref = ConanFileReference(*subdir.split(\"/\"))\n            if pattern:\n                if _partial_match(pattern, conan_ref):\n                    ret.append(conan_ref)\n\n        return sorted(ret)\n\n\ndef _partial_match(pattern, conan_ref):\n    \"\"\"\n    Finds if pattern matches any of partial sums of tokens of conan reference\n    \"\"\"\n    \n    tokens = str(conan_ref).replace('/', ' / ').replace('@', ' @ ').split()\n\n    def partial_sums(iterable):\n        sum = ''\n        for i in iterable:\n            sum += i\n            yield sum\n\n    return any(map(pattern.match, list(partial_sums(tokens))))\n\ndef search_packages(paths, reference, query):\n    \"\"\" Return a dict like this:\n\n            {package_ID: {name: \"OpenCV\",\n                           version: \"2.14\",\n                           settings: {os: Windows}}}\n    param conan_ref: ConanFileReference object\n    \"\"\"\n    infos = _get_local_infos_min(paths, reference)\n    return filter_packages(query, infos)\n\n\ndef _get_local_infos_min(paths, reference):\n    result = {}\n    packages_path = paths.packages(reference)\n    subdirs = list_folder_subdirs(packages_path, level=1)\n    for package_id in subdirs:\n        # Read conaninfo\n        try:\n            package_reference = PackageReference(reference, package_id)\n            info_path = os.path.join(paths.package(package_reference,\n                                                   short_paths=None), CONANINFO)\n            if not os.path.exists(info_path):\n                raise NotFoundException(\"\")\n            conan_info_content = load(info_path)\n            conan_vars_info = ConanInfo.loads(conan_info_content).serialize_min()\n            result[package_id] = conan_vars_info\n\n        except Exception as exc:\n            logger.error(\"Package %s has no ConanInfo file\" % str(package_reference))\n            if str(exc):\n                logger.error(str(exc))\n\n    return result\n", "path": "conans/search/search.py"}]}