为什么检查另一个字符串中是否存在空字符串时会返回 True?
- 2025-03-21 09:07:00
- admin 原创
- 44
问题描述:
我有限的大脑无法理解为什么会发生这种情况:
>>> print '' in 'lolsome'
True
在 PHP 中,等效比较返回 false(并发出警告):
var_dump(strpos('lolsome', ''));
解决方案 1:
来自文档:
对于 Unicode 和字符串类型,
x in y
当且仅当x是y的子字符串时才为真。等效测试是y.find(x) != -1
。注意,x和y不必是同一类型;因此,u'ab' in 'abc'
将返回True
。空字符串始终被视为任何其他字符串的子字符串,因此"" in "abc"
将返回True
。
从您的通话来看print
,您使用的是 2.x。
为了深入了解,请查看字节码:
>>> def answer():
... '' in 'lolsome'
>>> dis.dis(answer)
2 0 LOAD_CONST 1 ('')
3 LOAD_CONST 2 ('lolsome')
6 COMPARE_OP 6 (in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
COMPARE_OP
是我们进行布尔运算的地方,查看源代码可以in
发现比较发生的位置:
TARGET(COMPARE_OP)
{
w = POP();
v = TOP();
if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
/* INLINE: cmp(int, int) */
register long a, b;
register int res;
a = PyInt_AS_LONG(v);
b = PyInt_AS_LONG(w);
switch (oparg) {
case PyCmp_LT: res = a < b; break;
case PyCmp_LE: res = a <= b; break;
case PyCmp_EQ: res = a == b; break;
case PyCmp_NE: res = a != b; break;
case PyCmp_GT: res = a > b; break;
case PyCmp_GE: res = a >= b; break;
case PyCmp_IS: res = v == w; break;
case PyCmp_IS_NOT: res = v != w; break;
default: goto slow_compare;
}
x = res ? Py_True : Py_False;
Py_INCREF(x);
}
else {
slow_compare:
x = cmp_outcome(oparg, v, w);
}
Py_DECREF(v);
Py_DECREF(w);
SET_TOP(x);
if (x == NULL) break;
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
DISPATCH();
}
并且cmp_outcome 位于同一个文件中,很容易找到下一个线索:
res = PySequence_Contains(w, v);
这是在abstract.c中:
{
Py_ssize_t result;
if (PyType_HasFeature(seq->ob_type, Py_TPFLAGS_HAVE_SEQUENCE_IN)) {
PySequenceMethods *sqm = seq->ob_type->tp_as_sequence;
if (sqm != NULL && sqm->sq_contains != NULL)
return (*sqm->sq_contains)(seq, ob);
}
result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS);
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
}
为了从源头上找到答案,我们在文档中找到了下一个函数:
objobjproc PySequenceMethods.sq_contains
PySequence_Contains()
此函数可能由具有相同签名的函数使用。此槽可以保留为NULL,在这种情况下,PySequence_Contains()
只需遍历序列,直到找到匹配项。
并在同一文档中进一步阐述:
int PySequence_Contains(PyObject *o, PyObject *value)
确定o是否包含值。如果o中的某项等于值,则返回
1
,否则返回0
。如果发生错误,则返回-1
。这相当于 Python 表达式value in o
。
如果''
没有,则可以认为null
该序列包含它。'lolsome'
解决方案 2:
我深入挖掘并找到了与该函数对应的源代码strpos
,
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL, E_WARNING, "Empty needle");
RETURN_FALSE;
}
他们认为搜索空字符串是一个有问题的情况。因此,他们发出警告并返回false
。除此之外,我找不到任何文档讨论为什么将其视为问题。
就 Python 而言,此行为在“比较”部分中有很好的定义,
空字符串始终被视为任何其他字符串的子字符串,因此
"" in "abc"
将返回True
。
解决方案 3:
基本上,从数学上来说:
空集是每个集合的子集
同样的逻辑在这里也适用。你可以考虑''
一个空集。因此,它是每个字符串集的子集,因为它们必须是同一类型。
>>> a = ""
>>> b = "Python"
>>> a in b
True
>>> set(a).issubset(b)
True
>>> a = set() #empty set
>>> b = set([1,2,3])
>>> a.issubset(b)
True
>>>
但要小心!子集和成员资格是不同的东西。
解决方案 4:
空字符串是长度为零的唯一字符串。
空字符串是连接操作的标识元素。
空字符串按字典顺序位于任何其他字符串之前,因为它是所有字符串中最短的。
空字符串是合法的字符串,大多数字符串操作都应该适用于它。
维基百科
> strlen("");
=> 0
> "a" . "" == "a";
=> true
> "" . "a" == "a";
=> true
> "" < "