Как проверить, содержит ли строка только указанный набор символов? - PullRequest
3 голосов
/ 06 июля 2011

Я работаю со строкой, и мне интересно, каким способом лучше всего проверить, содержит ли строка только указанный набор символов:

@  ∆  SP  0  ¡  P  ¿  p 
£  _  !  1  A  Q  a  q 
$  Φ  "  2  B  R  b  r 
¥  Γ  #  3  C  S  c  s 
è  Λ  ¤  4  D  T  d  t 
é  O  %  5  E  U  e  u 
ù  Π  &  6  F  V  f  v 
ì  Ψ  '  7  G  W  g  w 
ò  Σ  (  8  H  X  h  x 
Ç  Θ  )  9  I  Y  i  y 
LF  Ξ  *  :  J  Z  j  z 
Ø  1)  +  ;  K  Ä  k  ä 
ø  Æ  ,  <  L  Ö  l  ö 
CR  æ  q  =  M  Ñ  m  ñ 
Å  ß  .  >  N  Ü  n  ü 
å  É  /  ?  O  §  o  à 

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

У кого-нибудь есть лучшее решение?

Заранее спасибо.

Ответы [ 6 ]

9 голосов
/ 08 июля 2011

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

Во-первых, я замечаю в ваших тегах на этот вопрос. Обратите внимание, что функции PHP ereg_ устарели; Вы должны использовать только функции preg_.

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

Класс символов - это список символов, заключенный в квадратные скобки. Вы можете отменить класс персонажа, добавив символ карата в его начало. Поэтому, если вам нужна строка, содержащая только «A», «B» или «C», и вы хотите получать предупреждения о строках, которые содержат что-то еще, вы можете использовать что-то вроде этого:

$result = preg_match("/[^ABC]/",$mystring);

Ваш пример в основном такой же (но с большим количеством символов для тестирования, очевидно), за исключением двух моментов: во-первых, в вашем списке есть символы, которые являются зарезервированными символами в Regex, а во-вторых, вы используете символы не-Ascii.

С зарезервированными символами Regex можно бороться, избегая их с помощью обратной косой черты. Вам просто нужно знать, какие символы зарезервированы. Глядя на ваш список, я вижу ?, /, . и +.

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

Вам все еще нужно указать движку регулярных выражений, что вы ищете символы Юникода. Это делается путем добавления модификатора u в конец строки регулярного выражения.

Таким образом, сокращенная версия вашего запроса может выглядеть следующим образом:

$result = preg_match("/[^èΛ¤4DTdt]/u",$mystring);

Похоже, что вы включаете новые строки в свой список символов, поэтому вы также можете добавить многострочный модификатор m вместе с этим u.

Для символов, которые не могут быть написаны (или даже для любого символа, если это проще), вы можете добавить escape-последовательности для их кодов символов Unicode. Используйте \uFFFF, где FFFF - шестнадцатеричная ссылка на юникод для символа, которому вы хотите соответствовать - например, \u00E0 соответствует à.

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

Надеюсь, это поможет.

3 голосов
/ 06 июля 2011

Что касается однобайтовых кодировок, вы можете сделать это с помощью строковой функции:

$charset = 'abc';
$test = 'abcd';
$ofCharset = strlen($test) === strspn($test, $charset); # FALSE

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

1 голос
/ 06 июля 2011

Чтобы сохранить операцию O (n), вы можете вычислить значение ascii каждого из ваших тестовых символов и поместить их в хеш-таблицу следующим образом:

$ testChars [$ ascii] = true;

Затем просто переберите символы строки темы и проверьте, установлена ​​ли запись значения в хэш-таблице и равна ли она истинному значению.Если вы получаете false для любого из символов, то он содержит символы, отсутствующие в вашем наборе тестов.

Это было бы лучше, чем использование in_array, потому что тестирование, если $ testChars [$ ascii] == true - это константа O (1) поиск.

0 голосов
/ 11 ноября 2013

Я знаю, что это старый вопрос, но никто не упомянул strpbrk .Я никогда не пробовал это с нечетными символами, но кроме того, что это может быть проблемой, почему бы это не сработало?

0 голосов
/ 07 июля 2011

если вы пытаетесь выяснить только, есть ли другие символы, вы можете просто str_replace установить набор символов в "" и затем получить strlen ... Если это 0, то только эти символы есть ... если больше 0тогда существуют другие символы.

напр.

$mystr = "macguffin";
$mycharset = array('m', 'a', 'c', 'g', 'u', 'f', 'i', 'n');

$tmpstr = str_replace($mycharset, "", $mystr);

if (!strlen($tmpstr)) {
    echo "only charset chars";
} else {
    echo "other chars";
}

вернет

only charset chars

, но

$mystr = "macguffin";
$mycharset = array('m', 'a', 'c');

$tmpstr = str_replace($mycharset, "", $mystr);

if (!strlen($tmpstr)) {
    echo "only charset chars";
} else {
    echo "other chars";
}

вернет

other chars

HTH

0 голосов
/ 06 июля 2011

Вот отличный ресурс, который может помочь вам найти ваш ответ.

Советы и приемы по усовершенствованным регулярным выражениям

...