Mar*_*sis 29 python string python-internals
我有限的大脑无法理解为什么会这样:
>>> print '' in 'lolsome'
True
Run Code Online (Sandbox Code Playgroud)
在PHP中,等效比较返回false:
var_dump(strpos('', 'lolsome'));
Run Code Online (Sandbox Code Playgroud)
小智 55
从文档:
对于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
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
并且cmp_outcome在同一个文件中,很容易找到我们的下一个线索:
res = PySequence_Contains(w, v);
Run Code Online (Sandbox Code Playgroud)
{
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);
}
Run Code Online (Sandbox Code Playgroud)
为了从源头获取空气,我们在文档中找到了下一个功能:
Run Code Online (Sandbox Code Playgroud)objobjproc PySequenceMethods.sq_contains此功能可以使用
PySequence_Contains()并具有相同的签名.此插槽可以保留为NULL,在这种情况下,PySequence_Contains()只需遍历序列直到找到匹配项.
Run Code Online (Sandbox Code Playgroud)int PySequence_Contains(PyObject *o, PyObject *value)确定o是否包含值.如果o中的项目等于value,则返回
1,否则返回0.出错,退货-1.这相当于Python表达式value in o.
如果''不是null,则'lolsome'可以认为序列包含它.
the*_*eye 20
引用PHP的strpos文档,
Run Code Online (Sandbox Code Playgroud)mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )查找的数字位置的第一次出现
needle中haystack字符串.
所以你实际尝试的内容类似于下面的Python构造
>>> print 'lolsome' in ''
False
Run Code Online (Sandbox Code Playgroud)
所以,您实际上应该如下所示编写,以便在PHP中进行相应的比较
var_dump(strpos('lolsome', ''));
Run Code Online (Sandbox Code Playgroud)
即使这样,它也会发出警告并返回false.
PHP警告::
strpos()第3行/home/thefourtheye/Desktop/Test.php中的空针
bool(false)
我深入挖掘并找到了与该strpos函数对应的源代码,
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL, E_WARNING, "Empty needle");
RETURN_FALSE;
}
Run Code Online (Sandbox Code Playgroud)
他们认为搜索的空字符串是一个有问题的案例.所以,他们正在发出警告并返回false.除此之外,我找不到任何文件讨论为什么它被视为一个问题.
就Python而言,此行为在" 比较"部分中已明确定义,
空字符串始终被视为任何其他字符串的子字符串,因此
"" in "abc"将返回True.
基本上,从数学:
空集是每个集的子集
这里的逻辑相同.你可以考虑''一个空集.因此,它是每个字符串集的子集,因为它们必须是相同的类型.
>>> 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
>>>
Run Code Online (Sandbox Code Playgroud)
不过要小心!子集和成员资格是不同的东西.
空字符串是长度为零的唯一字符串。
空字符串是串联操作的单位元素。
按照字典顺序,空字符串位于任何其他字符串之前,因为它是所有字符串中最短的。
空字符串是合法字符串,大多数字符串操作都可以在其上进行。
维基百科
> strlen("");
=> 0
> "a" . "" == "a";
=> true
> "" . "a" == "a";
=> true
> "" < "\0";
=> true
Run Code Online (Sandbox Code Playgroud)
从上面来看,PHP 似乎将空字符串视为有效字符串。
> strstr("lolsome", "");
strstr(): Empty needle :1
Run Code Online (Sandbox Code Playgroud)
但它似乎并不认为空字符串是完全合法的。PHP 很可能是唯一不允许在字符串中搜索空字符串子字符串的语言。
是一种防御机制吗?显然,程序员不必用 来保护针if。如果是这样,为什么其他语言允许这个测试通过!语言设计者必须回答
Python 字符串由什么组成?
>>> ''.count('')
1
Run Code Online (Sandbox Code Playgroud)
显然空串有一个空串。
>>> 'a'.count('')
2
Run Code Online (Sandbox Code Playgroud)
一个元素串有两个空串。
>>> 'ab'.count('')
3
Run Code Online (Sandbox Code Playgroud)
看来Python字符串是单元素字符串的串联。字符串中的每个元素都夹在两个空字符串之间。
>>> "lolsome".split('')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: empty separator
Run Code Online (Sandbox Code Playgroud)
但这里 Python 与空字符串的有效性相矛盾。这是一个错误吗?
Ruby和JavaScript通过了这里的测试。
> "lolsome".split("")
=> ["l", "o", "l", "s", "o", "m", "e"]
Run Code Online (Sandbox Code Playgroud)
我从Rosetta 代码中编译了几个语言示例,有趣的是它们都允许在子字符串搜索中使用空字符串并返回 true。
awk 'BEGIN { print index("lolsome", "") != 0 }'
Run Code Online (Sandbox Code Playgroud)
int main() {
printf("%d\n", strstr("lolsome", "") != NULL);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
#include <iostream>
#include <string>
int main() {
std::string s = "lolsome";
std::cout << (s.find("") != -1) << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
using System;
class MainClass {
public static void Main (string[] args) {
string s = "lolsome";
Console.WriteLine(s.IndexOf("", 0, s.Length) != -1);
}
}
Run Code Online (Sandbox Code Playgroud)
(println (.indexOf "lolsome" ""))
Run Code Online (Sandbox Code Playgroud)
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Index("lolsome", "") != -1)
}
Run Code Online (Sandbox Code Playgroud)
格罗维
println 'lolsome'.indexOf('')
Run Code Online (Sandbox Code Playgroud)
返回 0,出错时返回 -1
class Main {
public static void main(String[] args) {
System.out.println("lolsome".indexOf("") != -1);
}
}
Run Code Online (Sandbox Code Playgroud)
"lolsome".indexOf("") != -1
Run Code Online (Sandbox Code Playgroud)
s = "lolsome"
print(s:find "" ~= nil)
Run Code Online (Sandbox Code Playgroud)
print index("lolsome", "") != -1;
Run Code Online (Sandbox Code Playgroud)
"lolsome".find("") != -1
Run Code Online (Sandbox Code Playgroud)
"lolsome".index("") != nil
Run Code Online (Sandbox Code Playgroud)