Мой ограниченный мозг не может понять, почему это происходит:
>>> print '' in 'lolsome'
True
В PHP эквивалентное сравнение возвращает false:
var_dump(strpos('', 'lolsome'));
Мой ограниченный мозг не может понять, почему это происходит:
>>> print '' in 'lolsome'
True
В PHP эквивалентное сравнение возвращает false:
var_dump(strpos('', 'lolsome'));
Для 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
. Это эквивалентно выражению Pythonvalue in o
.
Где ''
не null
, можно считать, что последовательность 'lolsome'
содержит ее.
Цитата из PHP strpos
документации,
mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
Найти числовое положение первого вхождения
needle
в строкеhaystack
.
Итак, то, что вы на самом деле пытались, похоже на конструкцию Python, представленную ниже
>>> print 'lolsome' in ''
False
Итак, на самом деле вы должны написать, как показано ниже, чтобы иметь соответствующее сравнение в PHP
var_dump(strpos('lolsome', ''));
Даже тогда он выдает предупреждение и возвращает false
.
Предупреждение PHP:
strpos()
: пустая стрелка в /home/thefourtheye/Desktop/Test.php в строке 3
bool(false)
Я углубился и нашел исходный код, соответствующий функции strpos
,
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL, E_WARNING, "Empty needle");
RETURN_FALSE;
}
Они рассматривают пустую строку, которую ищут как проблемный случай. Таким образом, они выдают предупреждение и возвращают 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
>>>
Но будьте осторожны! Подмножество и членство разные вещи.
Пустая строка - это единственная строка нулевой длины.
Пустая строка - это элемент идентификации операции конкатенации.
Пустая строка предшествует любой другой строке в лексикографическом порядке, потому что она является самой короткой из всех строк.
Пустая строка - это законная строка, на которой должны работать большинство строковых операций.
Wikipedia
> strlen("");
=> 0
> "a" . "" == "a";
=> true
> "" . "a" == "a";
=> true
> "" < "\0";
=> true
Сверху кажется, что PHP обрабатывает пустую строку как допустимую строку.
> strstr("lolsome", "");
strstr(): Empty needle :1
Но он не считает пустую строку полностью легитимной. Скорее всего, PHP является единственным языком, который не позволяет искать подстроку в строке как пустую строку.
Это защитный механизм? Очевидно, что программистам не нужно защищать иглу if
. Если да, то почему другие языки позволяют пройти этот тест!!! Языковые дизайнеры должны отвечать
Какая строка Python состоит из?
>>> ''.count('')
1
Очевидно, что пустая строка имеет одну пустую строку.
>>> 'a'.count('')
2
Одна строка элемента имеет два пустых srings.
>>> 'ab'.count('')
3
Итак, кажется, что строка Python является конкатенацией одной строки элемента. Каждый элемент в строке зажат между двумя пустыми строками.
>>> "lolsome".split('')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: empty separator
Но здесь Python противоречит действительности пустой строки. Это ошибка?
Ruby и JavaScript проходят здесь тест.
> "lolsome".split("")
=> ["l", "o", "l", "s", "o", "m", "e"]
Я собрал несколько примеров из Rosetta code, интересно отметить, что все они разрешают пустую строку в поиске подстроки и возвращают true.
awk 'BEGIN { print index("lolsome", "") != 0 }'
int main() {
printf("%d\n", strstr("lolsome", "") != NULL);
return 0;
}
#include <iostream>
#include <string>
int main() {
std::string s = "lolsome";
std::cout << (s.find("") != -1) << "\n";
return 0;
}
using System;
class MainClass {
public static void Main (string[] args) {
string s = "lolsome";
Console.WriteLine(s.IndexOf("", 0, s.Length) != -1);
}
}
(println (.indexOf "lolsome" ""))
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Index("lolsome", "") != -1)
}
Groovy
println 'lolsome'.indexOf('')
возвращает 0, при ошибке возвращается -1
class Main {
public static void main(String[] args) {
System.out.println("lolsome".indexOf("") != -1);
}
}
"lolsome".indexOf("") != -1
s = "lolsome"
print(s:find "" ~= nil)
print index("lolsome", "") != -1;
"lolsome".find("") != -1
"lolsome".index("") != nil
Предположим, у вас есть две груды похожих предметов, например, лучшие строфы вашего любимого поэта, 5 и 2 соответственно. Большой набор содержит меньший набор? Как проверить: 1) для любой строфы в меньшей куче вы можете найти ее в более крупной. 2) меньшая куча не содержит чего-то, чего нет в более крупном.
Таким образом, мы можем использовать этот псевдокод для проверки:
for object in smaller:
if object not in bigger:
return 'we found object from smaller absent in bigger'
else:
go to next object
return 'all is ok - all objects from smaller are in bigger'
Если вы не нашли такого объекта, вы подходите к концу algo и считаете, что меньше - это подмножество большего размера.
Теперь представьте меньшую кучу 0 строф. Применяя те же правила выше, мы выполняем 0 проверок, а также не находим объект меньшего размера, который больше отсутствует.
Итак, правильно и удобно считать пустую строку как подмножество любой другой строки. Даже сам. И это реализовано в python.
>>> '' in 'adfsf'
True
>>> '' in ''
True