В Python, как проверить, содержит ли строка только определенные символы?

Если Вы объявите переменную в функциональных помехах, то его значение не будет сохранено на стопке вызова функции и все еще будет доступно, когда Вы вызовете функцию снова.

, Если Вы объявляете статичную глобальную переменную, ее объем будет ограничен в файле, в котором Вы объявили это. Это немного более безопасно, чем постоянный клиент, глобальный, который может быть считан и изменен всюду по Вашей всей программе.

46
задан Peter Mortensen 1 September 2010 в 11:26
поделиться

4 ответа

Final (?) Edit

Ответ, завернутый в функцию, с аннотированным интерактивным сеансом:

>>> import re
>>> def special_match(strg, search=re.compile(r'[^a-z0-9.]').search):
...     return not bool(search(strg))
...
>>> special_match("")
True
>>> special_match("az09.")
True
>>> special_match("az09.\n")
False
# The above test case is to catch out any attempt to use re.match()
# with a `$` instead of `\Z` -- see point (6) below.
>>> special_match("az09.#")
False
>>> special_match("az09.X")
False
>>>

Примечание. Ниже в разделе приводится сравнение с использованием re.match () этот ответ. Дальнейшие тайминги показывают, что match () выиграет с гораздо более длинными строками; Если окончательный ответ - True, у match () гораздо больше накладных расходов, чем у search (); это вызывает недоумение (возможно, это стоимость возврата MatchObject вместо None) и может потребовать дальнейшего изучения.

==== Earlier text ====

В [ранее] принятом ответе можно было бы использовать несколько улучшений:

(1) Представление дает видимость результат интерактивного сеанса Python:

reg=re.compile('^[a-z0-9\.]+$')
>>>reg.match('jsdlfjdsf12324..3432jsdflsdf')
True

, но match () не возвращает True

(2) Для использования с match () ^ в начале шаблона будет избыточный, и, кажется, немного медленнее, чем тот же шаблон без ^

(3) Должен автоматически способствовать использованию необработанной строки для любого повторного шаблона

(4) Обратная косая черта перед точкой / точкой избыточно

(5) Медленнее, чем код OP!

prompt>rem OP's version -- NOTE: OP used raw string!

prompt>\python26\python -mtimeit -s"t='jsdlfjdsf12324..3432jsdflsdf';import
re;reg=re.compile(r'[^a-z0-9\.]')" "not bool(reg.search(t))"
1000000 loops, best of 3: 1.43 usec per loop

prompt>rem OP's version w/o backslash

prompt>\python26\python -mtimeit -s"t='jsdlfjdsf12324..3432jsdflsdf';import
re;reg=re.compile(r'[^a-z0-9.]')" "not bool(reg.search(t))"
1000000 loops, best of 3: 1.44 usec per loop

prompt>rem cleaned-up version of accepted answer

prompt>\python26\python -mtimeit -s"t='jsdlfjdsf12324..3432jsdflsdf';import
re;reg=re.compile(r'[a-z0-9.]+\Z')" "bool(reg.match(t))"
100000 loops, best of 3: 2.07 usec per loop

prompt>rem accepted answer

prompt>\python26\python -mtimeit -s"t='jsdlfjdsf12324..3432jsdflsdf';import
re;reg=re.compile('^[a-z0-9\.]+$')" "bool(reg.match(t))"
100000 loops, best of 3: 2.08 usec per loop

(6) Может дать неправильный ответ !!

>>> import re
>>> bool(re.compile('^[a-z0-9\.]+$').match('1234\n'))
True # uh-oh
>>> bool(re.compile('^[a-z0-9\.]+\Z').match('1234\n'))
False
35
ответ дан 26 November 2019 в 20:07
поделиться

Вот простая реализация на чистом Python. Его следует использовать, когда производительность не критична (включено для будущих сотрудников Google).

import string
allowed = set(string.ascii_lowercase + string.digits + '.')

def check(test_str):
    set(test_str) <= allowed

Что касается производительности, итерация, вероятно, будет самым быстрым методом. Регулярные выражения должны проходить через конечный автомат, а решение равенства наборов должно создавать временный набор. Однако вряд ли разница будет иметь большое значение. Если производительность этой функции очень важна, напишите ее как модуль расширения C с оператором switch (который будет скомпилирован в таблицу переходов).

Вот реализация C, который использует операторы if из-за нехватки места. Если вам абсолютно необходима крошечная дополнительная скорость, запишите корпус переключателя. В моих тестах он работает очень хорошо (2 секунды против 9 секунд в тестах с регулярным выражением).

#define PY_SSIZE_T_CLEAN
#include <Python.h>

static PyObject *check(PyObject *self, PyObject *args)
{
        const char *s;
        Py_ssize_t count, ii;
        char c;
        if (0 == PyArg_ParseTuple (args, "s#", &s, &count)) {
                return NULL;
        }
        for (ii = 0; ii < count; ii++) {
                c = s[ii];
                if ((c < '0' && c != '.') || c > 'z') {
                        Py_RETURN_FALSE;
                }
                if (c > '9' && c < 'a') {
                        Py_RETURN_FALSE;
                }
        }

        Py_RETURN_TRUE;
}

PyDoc_STRVAR (DOC, "Fast stringcheck");
static PyMethodDef PROCEDURES[] = {
        {"check", (PyCFunction) (check), METH_VARARGS, NULL},
        {NULL, NULL}
};
PyMODINIT_FUNC
initstringcheck (void) {
        Py_InitModule3 ("stringcheck", PROCEDURES, DOC);
}

Включите его в свой setup.py:[12111 sizes Используйте как:

>>> from stringcheck import check
>>> check("abc")
True
>>> check("ABC")
False
58
ответ дан 26 November 2019 в 20:07
поделиться

Более простой подход? Еще немного Pythonic?

>>> ok = "0123456789abcdef"
>>> all(c in ok for c in "123456abc")
True
>>> all(c in ok for c in "hello world")
False

Конечно, он не самый эффективный, но вполне читаемый.

29
ответ дан 26 November 2019 в 20:07
поделиться

РЕДАКТИРОВАТЬ: Изменено регулярное выражение, чтобы исключить AZ

Решение с использованием регулярных выражений является самым быстрым решением на чистом питоне на данный момент

reg=re.compile('^[a-z0-9\.]+$')
>>>reg.match('jsdlfjdsf12324..3432jsdflsdf')
True
>>> timeit.Timer("reg.match('jsdlfjdsf12324..3432jsdflsdf')", "import re; reg=re.compile('^[a-z0-9\.]+$')").timeit()
0.70509696006774902

По сравнению с другими решениями:

>>> timeit.Timer("set('jsdlfjdsf12324..3432jsdflsdf') <= allowed", "import string; allowed = set(string.ascii_lowercase + string.digits + '.')").timeit()
3.2119350433349609
>>> timeit.Timer("all(c in allowed for c in 'jsdlfjdsf12324..3432jsdflsdf')", "import string; allowed = set(string.ascii_lowercase + string.digits + '.')").timeit()
6.7066690921783447

Если вы хотите разрешить пустое strings затем измените его на:

reg=re.compile('^[a-z0-9\.]*$')
>>>reg.match('')
False

По запросу я собираюсь вернуть другую часть ответа. Но обратите внимание, что следующие значения принимают диапазон AZ. Джон привел пример, когда вышеуказанное не работает. Я изменил решение, чтобы преодолеть этот частный случай, используя encode

test_str.replace('.', '').encode('ascii', 'replace').isalnum()

. И оно все еще почти в 3 раза быстрее, чем заданное решение

timeit.Timer("u'ABC\u0131\u0661'.encode('ascii', 'replace').replace('.','').isalnum()", "import string; allowed = set(string.ascii_lowercase + string.digits + '.')").timeit()
1.5719811916351318

. На мой взгляд, использование регулярных выражений - лучшее решение этой проблемы

14
ответ дан 26 November 2019 в 20:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: