Определите, является ли строка camelCase

Я пытаюсь заставить PHP_CodeSniffer проверить camelCase в именах классов, однако мне кажется, что проверка camelCase невозможна (без словаря, в том числе обидчивый слова).

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

И даже это бесполезно, поскольку проверка может быть точной, только если имя точно / всегда содержал разделитель между каждым словом.
И точка «проверки» будет заключаться в том, чтобы определить, правильно ли отформатировано имя, и это может включать неправильное разделение.

Кроме того, ресурсы в PHP_CodeSniffer либо редки, либо настолько просты и понятны, что их понимает только автор / разработчик.

Текущие Стандартные Проверки Sniff

Я нашел этот код в некоторых из текущих Sniffs (то есть стандартов Squiz и PEAR):

if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, false) === false)

Тем не менее, я посмотрел на основной код PHP_CodeSniffer, и эта функция только делает следующее:

// Check the first character first.
// Check that the name only contains legal characters.
// Check that there are not two capital letters next to each other.
// The character is a number, so it cant be a capital.

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

Вопрос

Как может Sniff (или, например, PHP-скрипт) знать, какие «слова» нужно проверить в данной строке, чтобы определить, является ли строка 100% camelCase?


РЕДАКТИРОВАТЬ

Примеры

Правильный camelCase: class calculateAdminLoginCount

// Not camelCase
class calculateadminlogincount

// Partially camelCase
class calculateadminLogincount

Как можно isCamelCaps() функция (или любой PHP-скрипт в этом отношении) ловит два приведенных выше примера?

Как может функция или PHP-скрипт идентифицировать «отдельные слова» из строки, если в ней нет понятия «слова», не передавая ей эту информацию (т.е. из словаря)?

Даже если сценарий, где взорваться, что бы он взорвался на основе?

принимать class calculateadminLogincount
Как любой скрипт PHP может идентифицировать это calculate admin Login count разные слова в этой строке, чтобы потом можно было проверить, если: 1-я буква 1-е слово строчная, тогда все последующие слова 1-я буква заглавная?

isCamelCaps() функция

public static function isCamelCaps(
$string,
$classFormat=false,
$public=true,
$strict=true
) {

// Check the first character first.
if ($classFormat === false) {
$legalFirstChar = '';
if ($public === false) {
$legalFirstChar = '[_]';
}

if ($strict === false) {
// Can either start with a lowercase letter,
// or multiple uppercase
// in a row, representing an acronym.
$legalFirstChar .= '([A-Z]{2,}|[a-z])';
} else {
$legalFirstChar .= '[a-z]';
}
} else {
$legalFirstChar = '[A-Z]';
}

if (preg_match("/^$legalFirstChar/", $string) === 0) {
return false;
}

// Check that the name only contains legal characters.
$legalChars = 'a-zA-Z0-9';
if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) {
return false;
}

if ($strict === true) {
// Check that there are not two capital letters
// next to each other.
$length          = strlen($string);
$lastCharWasCaps = $classFormat;

for ($i = 1; $i < $length; $i++) {
$ascii = ord($string{$i});
if ($ascii >= 48 && $ascii <= 57) {
// The character is a number, so it cant be a capital.
$isCaps = false;
} else {
if (strtoupper($string{$i}) === $string{$i}) {
$isCaps = true;
} else {
$isCaps = false;
}
}

if ($isCaps === true && $lastCharWasCaps === true) {
return false;
}

$lastCharWasCaps = $isCaps;
}
}//end if

return true;

}//end isCamelCaps()

РЕДАКТИРОВАТЬ 2

Немного информации для тех, кто интересуется, стоит ли это того или нет, или я просто «бездельничаю» и «получаю удовольствие»:

Обязательно, чтобы имена классов были правильно названы повсюду, поскольку структура файла / папки, а также имена и имена классов должны совпадать, чтобы автозагрузчик работал без сбоев.

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

1

Решение

Вы можете проанализировать имена функций на предмет правильного использования заглавных букв, разбив слово, где происходит переход к регистру. Для каждой части исходного имени функции найдите это подслово в словаре или файле словаря + жаргон («calc», «url», «admin» и т. Д. (Возможно, сначала проверьте жаргон)). Если какое-либо подслово терпит неудачу, то надлежащая капитализация не на месте.

Вы можете использовать Solr или ElasticSearch, чтобы разбить ваши слова на части с помощью WordDelimiterFilter в Lucene. Это создаст подслов при изменении регистра:

"PowerShot" -> "Power" "Shot""LoginURL" => "Login" "URL"

Вы можете либо вставить слова непосредственно в эти базы данных NoSQL и выполнить анализ позже, либо вы можете (по крайней мере, в ES) просто использовать фильтр токенов разделителя слов, чтобы разбить ваш запрос без фактического сохранения результатов.

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html

https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.WordDelimiterFilterFactory

Пример:

calcAdminLogin => calc Admin Войти

calcadminlogin => calcadminlogin

Если у вас есть дополнительный словарь, который содержит такие слова, как «calc» и «admin», то имя первой функции будет разложено на 3 слова, которые будут присутствовать в словаре, поэтому верблюд верен.

Во втором примере ‘calcadminlogin’ не будет найден в словаре, поэтому верблюжий регистр неверен.

0

Другие решения

Я сделал несколько сценариев, чтобы попытаться «свободно» определить, является ли имя класса CamelCase.

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

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

Критика очень приветствуется.


Разрешить только альфа-регистр

Это гарантирует, что имя класса содержит только прописные или строчные буквенные буквы (Az), которые необходимы для проверок camelCase (если вы удалите этот сценарий, вам придется изменить другие сценарии, чтобы приспособиться к потенциалу не-альфа символы).

/** Check string is only alpha (A-z) */
if (ctype_alpha($name) === false) {
$error = '%s name must only contain alpha chars (A-z)';
$phpcsFile->addError($error, $stackPtr, 'AlphaChars', $errorData);
return;
}

Нет двух заглавных букв вместе

Некоторые стандарты допускают аббревиатуры и т. Д., Однако мои стандарты не допускают этого, так как это не строгий camelCase и нарушает поток чтения.

например userSitePHPLogin является недействительным, и userSitePhpLogin является действительным.

(Существует более элегантный способ сделать это, но он работает нормально, и учитывая, что он для PHP_CodeSniffer, мне не нужна микрооптимизация)

/** Check for uppercase chars together */
$nameUppercaseExplode = preg_split('/(?=[A-Z])/', $name);
$totalIllegalUpperChars = 0;

foreach ($nameUppercaseExplode as $namePiece) {
if (strlen($namePiece) == 1) {
$totalIllegalUpperChars++;
}
}

if ($totalIllegalUpperChars >0) {
$warning = 'Class name seems invalid;
Total '.$totalIllegalUpperChars.' uppercase chars not part of camelCase';
$phpcsFile->addWarning($warning, $stackPtr, 'UppercaseTogether', $errorData);
}

например имя класса DUserPHPUserclassLogin возвращает:

Имя класса кажется неверным; Всего 4 заглавных буквы, не являющихся частью camelCase

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

например имя класса classDUserPhpUserLogin возвращает:

Имя класса кажется неверным; Всего 1 заглавные буквы не являются частью camelCase

Так что это, по крайней мере, побуждает разработчика проверить имя и исправить его соответствующим образом.


Проверьте, если общее количество символов в верхнем регистре меньше общего количества слов

Благодаря sjagr для идеи.

«Всего слов» — это, конечно, «угаданная» цифра, основанная на среднем 5 знаков для каждого слова — потому что кажется, что официальное среднее значение составляет около 4,7 знаков для каждого слова.

/** Loose check if total (guessed) words not match total uppercase chars */
$totalWordsGuess = ceil(strlen($name) / 5);
$totalUpperChars = strlen(preg_replace('![^A-Z]+!', '', $name));

// Pointless if only 1 word (camelCase not exist)
if ($totalWordsGuess >1) {

// Remove the first word which should be lowercase
// (first word should be checked in separate check above this one)
$totalWordsGuess--;

if ($totalUpperChars < $totalWordsGuess) {
$warning = 'Expected '.$totalWordsGuess.' camelCase words in class name;
Found '.$totalUpperChars;
$phpcsFile->addWarning($warning, $stackPtr, 'BadCamelCase', $errorData);
}

}

Я проверил это и работает довольно хорошо (это только предупреждение для потенциал проблемы).

Например, используя имя класса UserLoginToomanywordsWithoutcamelCasePHP_CodeSniffer возвращает:

Ожидаемые 7 слов camelCase в названии класса; Найдено 5

Если возвращается слишком много ложных срабатываний (разные разработчики используют разные слова и т. Д.), То настройте текущее значение «5» вверх или вниз на ступеньку выше.

редактировать: Обновлен этот скрипт выше:

  • Добавлено условие, чтобы скрипт выполнялся, только если более 1 слова, как 1 слово
    не может быть верблюдом.
  • Добавлен код для вычитания 1 из общего количества угаданных слов (var --), чтобы
    учитывать первое слово в нижнем регистре и поэтому не в верхнем регистре
    будет существовать для этого.

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

0