Поиск…


замечания

В VFP операторы сгруппированы в те:

  • Числовые операторы
  • Логические операторы
  • Операторы символов
  • Операторы даты и времени
  • Реляционные операторы

Также существуют операторы, реализованные как функции (такие как побитовые операции, сравнение объектов ...).

Мы рассмотрим каждый пример.

Числовые операторы

Числовые операторы являются самыми легкими и почти такими же, как на других языках.

  • +, -, * и /. Операторы сложения, вычитания, умножения и деления (в VFP нет целочисленного деления, вы можете преобразовать результат в целое число с функциями INT (), CEILING () и FLOOR ()).
  • % Оператор модуля.
  • ^ и **. Мощность оператора (ов). Они оба делают то же самое.
  • (). Группировка операторов.
  • У операторов есть приоритет. Заказ:
   ( )
   ^ (or **) 
   / and *
   - and +
    ? 10 / 5 + 2 && Outputs 4
    ? 2 + 10 / 5 && Outputs 4 as well. Division has precedence.
     
    * Both multiplication and division have same precedence
    * They would be interpreted from left to right.
    ? 4 * 5 / 2 + 5 && Outputs 15
    * Use parentheses whenever you are in doubt or want to be explicit
    ? ( (4 * 5) / 2 ) + 5 && Outputs 15. Explicit grouping of operations

    ? 4 * 5^2 && ^ has precedence, this is same as 4 * (5^2) = 100.
    ? (4 + 5)^2 && Using parentheses we say add 5 to 4 (9) and then square = 81. 

Логические операторы

Логические операторы в VFP в порядке их очередности:

оператор Описание
() Скобки, выражения групп
НЕ,! Логически отрицать выражение. НЕ или! не имеет никакой разницы.
А ТАКЖЕ Логически И выражения
ИЛИ ЖЕ Логически ИЛИ выражения
<>,! =, # Проверьте неравенство. Таким же образом, как логический исключающий OR - XOR

Исторически, NOT, AND, OR написаны как .NOT., .AND., .OR. Вы можете использовать их, если хотите, но И, ИЛИ, НЕ - проще и чище.

Для ложных и истинных вы должны использовать .F. и т. соответственно. Вместо этого вы не можете использовать F и T.

* Some logical variables
local llOld, llEmail  && any variable declaration implicitly initializes the variable as .F. - false
? m.llOld, m.llEmail && Prints .F. .F.

llOld   = .T.
llEmail = .F.

if ( m.llOld AND m.llEmail )
   ? 'Old AND should be emailed to'
endif
if ( m.llOld OR m.llEmail )
   ? 'Old OR should be emailed to'
endif
if ( m.llOld AND !m.llEmail ) && Same as (m.llOld AND NOT m.llEmail)
   ? 'Old BUT should NOT be emailed to'
endif

* Above code outputs
Old OR should be emailed to
Old BUT should NOT be emailed to

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

? 1 = '2' && An obvious error. It would complain operator/operand type mismatch.

* However we could use such an expression in an if and get no error
* because it is not interpreted at all 
* (VFP is dynamic and there is no compile time check)

local llProcess
llProcess = .T.

if (m.llProcess OR (1='2'))
   ? 'Should do processing'
endif

* Would output

Should do processing

* without any error because m.llProcess true means
* the whole expression would be true, thus the expression after OR 
* is not interpreted at all.

Одна ловушка, которая ловит новичков, заключается в том, что иногда вам может потребоваться несколько проверок, например, в SQL-запросе, которые связаны с операторами AND и OR. Когда их много, можно игнорировать тот факт, что операторы имеют приоритет (в порядке (), NOT, AND, OR) и считают, что интерпретация будет выполняться слева направо в цепочке. Рассмотрим образец:

select * from myTable where !isCustomer AND debit > 5000 OR discount > 5

Какова цель этого запроса? Если мы сделаем это явным, используя группирующие круглые скобки, он говорит:

((NOT isCustomer) AND debit > 5000) OR discount > 5

упрощенное выражение выглядит как «firstExpression» ИЛИ (скидка> 5). Каким бы ни было намерение, из-за этого ИЛИ он выбрал бы:

все строки, которые имеют (скидка> 5), а также те, где он является клиентом с более чем 5000 дебетом.

Вероятно, намерение состояло в том, чтобы «дать мне те, где он НЕ является клиентом И (дебет превышает 5000 или скидка превышает 5)». С самого начала было бы ясно, если мы будем использовать круглые скобки:

select * from myTable where !isCustomer AND (debit > 5000 OR discount > 5)

Вы можете использовать, но не стоит иметь круглые скобки для исходного оператора NOT, когда его операнд является единственным выражением, достаточно читаемым с его приоритетом -! IsCustomer явно читается как (NOT isCustomer).

Операторы символов

Есть только 4 символьных оператора в порядке очередности:

оператор Описание
() Скобки для группировки. Примечание. Документация VFP, которую я имею, пропускает этот. Без этого оператор почти всегда бесполезен.
+ Сочетает (объединяет) строки рядом.
- Переключает строки, перемещая конечные пробелы из левой строки в конец правой строки.
$ Проверяет, содержит ли первая строка второй.

+ является самым простым и также используется для конкатенации строк на многих других языках.

local firstName, lastName
firstName = "John"
lastName  = "Smith"

? m.firstName + " " + m.lastName

Выводы: Джон Смит

- немного сложно, и не широко известно. Он берет конечные пробелы из левой строки, добавляет эти пробелы в строку справа. Предположим, у вас есть таблица с именами и фамилиями, каждая из которых имеет 20 символов. Мы хотим объединить имя и фамилию, чтобы создать полное имя, и мы также хотим, чтобы результирующий размер был исправлен (в данном случае 20 + 20 + 1 пробел = 41). Давайте сделаем так, что у вас также есть столбец среднего имени, и мы хотим, чтобы полное имя выглядело как «lastName, firstName middleName_______». Это проще всего сделать с помощью оператора - но вы должны отметить трюк использования круглых скобок здесь для группировки, чтобы мы получили именно то, что хотим:

* Create a cursor for our sample and fill in a few names
Create Cursor Names (firstName c(20), midName c(20), lastName c(20))

Insert Into Names (firstName, midName, lastName) Values ('Cetin','', 'Basoz')
Insert Into Names (firstName, midName, lastName) Values ('John', 'M', 'Smith')
Insert Into Names (firstName, midName, lastName) Values ('John', 'F', 'Kennedy')
Insert Into Names (firstName, midName, lastName) Values ('Tom', '', 'Hanks')

* Select with tricky - operator
Select *, ;
    lastName - (', '+firstName-(' '+midName)) As FullName ;
    from Names ;
    INTO Cursor crsNames ;
    nofilter

Browse

И выход такой:

имя midName Фамилия ФИО
Четин Basoz Базоз, Цетин
Джон M кузнец Смит, Джон М
Джон F Кеннеди Кеннеди, Джон Ф.
Том Hanks Хэнкс, Том

В столбце fullName все конечные пробелы отлично доводятся до конца. Если вы проверите структуру fullName, то столбец будет иметь 63 символа (3 * 20 + 3 символа, которые мы добавили).

Обратите внимание на важность группировки круглых скобок (попробуйте удалить скобки или упорядочить по-другому).

Хотя в этом случае у оператора может возникнуть соблазн использовать другую сторону монеты. Этот оператор специфичен для VFP, поэтому SQL не переносится. Вы можете добиться того же результата с помощью этого ANSI-совместимого SQL:

Select *, ;
    CAST(RTRIM(lastName) +', '+ RTRIM(firstName) +' '+ midName as char(63)) As FullName ;
    from Names ;
    INTO Cursor crsNames ;
    nofilter

Последний оператор равен $. Он просто проверяет, является ли левая строка частью правильной строки.

local upcased, digits, hexDigits
upcased = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digits  = '0123456789'
hexDigits  = m.digits + 'ABCDEF'

? 'A' $ m.upcased && .T.
? 'a' $ m.upcased && .F.
? '1' $ m.digits && .T.
? 'F' $ m.digits && .F.
? 'F' $ m.hexDigits && .T.

Важно: В VFP, хотя вы можете написать свой код в любом случае (верхний, нижний или смешанный), строки всегда чувствительны к регистру. Например: «Смит» и «кузнец» - это два разных значения. Или в вашем столе, если есть столбец страны, вы не найдете «США», если будете искать его с помощью «usa». То же самое происходит с оператором $, «GE» $ «Германия» является ложным.

Личное примечание. Хотя вам может понравиться $ за его простоту, и вы можете найти его часто используемым в исходных кодах Microsoft, IMHO он имеет очень мало значения. Думая о многих тысячах строк, которые я написал на моем носителе, я думаю, что в моем собственном коде найду очень мало случаев. Почти всегда есть лучшая альтернатива (особенно, когда левый операнд не является ни одним символом, ни вопросом чувствительности к регистру).

Операторы даты и времени

В настоящее время существуют два оператора для дат, значений даты и времени. + и - перегружены (возможно, термин C), чтобы сделать математику date / datetime:

оператор Описание
+ Добавляет дни (дата) или секунды (datetime) в значение date / datetime.
- Получает разницу двух значений даты / даты. Вычитает дни (дата) или секунды (datetime) из значений даты и времени.

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

Если одним из операндов является дата, то числовой операнд принимается как «день»:

? Date() + 10 && Get the date 10 days later
* VFP is leap year aware when doing date math
? Date(2016, 2, 28) + 1 && Add 1 day to Feb 28, 2016. Returns Feb 29, 2016.
? Date(2017, 2, 28) + 1 && Add 1 day to Feb 28, 2017. Returns Mar 1, 2017.

Если одним из операндов является дата-время, то числовой операнд принимается как «секунда»:

Есть 24 * 60 * 60 = 86400 секунд в день

? Datetime() + 86400 && Add 1 day to current datetime. 

Добавить 4 часа и 15 минут до 1 января 2016 года 14:20

? Datetime(2016, 1, 1, 14, 20, 0) + (4 * 3600 + 15 * 60) 

Выходы Пятница, 1 января 2016 года, 6:35:00.

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

Существует один специальный символ ^ для даты и времени, заставляющий строку интерпретировать «строго» как формат yyyy / MM / dd [HH: mm: ss | hh: mm: ss tt]. Поэтому ^ можно считать оператором даты и даты. Например, рассмотрим, что некоторые данные поступают из источника в формате 201610082230 (yyyyMMddHHmm). Чтобы получить это значение как действительное Datetime:

Local cSample, tSample
cSample = '201610082230'
tSample = Ctot(Transform(m.cSample, '@R ^9999/99/99 99:99'))
? Transform(m.tSample, '@YL')

Выходы (в зависимости от устаревших настроек вашей системы):

Суббота, 8 октября 2016 года, 10:30:00

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

Начнем с более простых чисел даты / даты и времени и числовых операндов (например, с помощью оператора +):

Если одним из операндов является дата, то числовой операнд принимается как «день»:

? Date() - 10 && What was the date 10 days ago?
? Date(2016, 3, 1) - 1 && Returns Feb 29, 2016.
? Date(2017, 3, 1) - 1 && Returns Feb 28, 2017.

Если одним из операндов является дата-время, то числовой операнд принимается как «секунда»:

? Datetime() - 86400 && Go back exactly one day

Получите 1 час 30 минут назад от "now":

? Datetime() - (1 * 3600 + 30 * 60) 

Вторая форма заключается в том, чтобы получить разницу между двумя значениями date / datetime. Операнды - это дата и дата и время, вы не можете одновременно использовать дату и дату и время (при необходимости преобразовывайте тип преобразования, VFP не делает этого для вас). Правила такие же, как в + и -, операнды - это дата, тогда разница в днях , операнды - это дата и время, тогда разница в секундах .

Сколько дней до нового года (на 2016 год)?

? Date(2016, 12, 31) - Date()

Сколько секунд осталось до полуночи?

? Dtot(Date()+1) - Datetime()

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

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

Операторы отношения

Из всех операторов реляционные операторы являются самыми сложными, поэтому мы оставили их до конца.

Реляционные операторы также известны как операторы сравнения, они используются для сравнения вещей.

Результатом сравнения является логическое значение false или true.

Интересно, однако, если вы проверите его в VFP, вы сможете увидеть только операции с коротким списком и еще несколько строк, как будто это все об этих операторах.

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

Начнем со списка реляционных операторов:

оператор Описание Основной образец MOST
> Лучше чем ? 1> 2 && .F.
< Меньше, чем ? 1 <2 && .T.
> = Больше или равно ? 1> = 2 && .F.
<= Меньше или равно ? 1 <= 2 && .T.
знак равно Равно ? 1 = 1 && .T.
== Точно равно (имеет смысл для строк) ? '1' = '1' && .T.
! =, #, <> Не равно (все три оператора действуют одинаково, выбирают ваш любимый) ? 1! = 1 && .F.

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

Дата и дата-время можно сравнить, хотя они разные, VFP делает это неявно для вас.

? Date() > DateTime() && .F. 
? Date() <= DateTime() && .T. 
? Date() < DateTime() && .T. if it is not midnight

Когда операнды являются числовыми, все эти операторы просты и прямолинейны, они работают так, как в математическом выражении.

С логическими операндами, .F. считается меньше .T.

С объектами мы сравниваем ссылку на объект в памяти. Таким образом, наиболее часто используемое сравнение состоит в том, чтобы определить, указывают ли две объектные переменные на один и тот же объект. то есть:

local o1, o2
o1 = createobject('Label')
o2 = createobject('Label')
? m.o1 = m.o2 && is o1 and o2 the same object?
? m.o1 > m.o2 && this would work too but likely you would never use

* remember we are comparing their references in memory
* 
* They are different objects, but do they have any difference in their properties?
? CompObj(m.o1, m.o2) && .T. They are identical properties wise

Сравнение типа символьных данных, так как сравнение строк является наиболее запутанным в VFP. Он не работает, как на других языках и / или базах данных, и уникален для VFP (и, возможно, для некоторого другого языка xBase).

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

Сравнение в основном о том, чтобы быть равным или нет. Если они не равны, то мы можем думать о операторах>, <,> =, <=, right? С строками это запутывает, когда две строки считаются равными .

Важно: строки VFP чувствительны к регистру. «A» и «a» - две различные строки. Это не относится ко многим базам данных, где по умолчанию используется нечувствительная к регистру сортировка. Например, в postgreSQL или MS SQL Server в таблице, созданной с учетом нечувствительности к регистру (CI):

select * from myTable where Country = 'TURKEY'

select * from myTable where Country = 'Turkey'

даст тот же результат. В VFP, хотя вы получаете только те, где спички корпуса. Однако VFP имеет некоторую поддержку сопоставления и делает сравнение без учета регистра. (Не верьте, см. Ниже)

  • Если две строки не равны, насколько это хорошо, при условии, что вы не изменили значения по умолчанию, они сравниваются на основе их значений ASCII .

    ? 'Basoz' < 'Cetin' && is true.
    ? 'basoz' < 'Cetin' && is false.
    ? 'Cetin' < 'David' && is true.
    ? 'Çetin' < 'David' && is false.
    

По умолчанию для сопоставления используется «машина», и это то, что вы получаете. Когда вы меняете сопоставление на что-то еще, вы получаете сравнение, основанное на порядке сортировки сортировки. При настройке сортировки, отличной от машины по умолчанию, вы также подразумеваете нечувствительность к случаю при сравнении (не доверяйте этому для равенства):

  set collate to 'GENERAL'
  ? 'Basoz' < 'Cetin'
  ? 'basoz' < 'Cetin'
  ? 'Cetin' < 'David'
  ? 'Çetin' < 'David'

Теперь все эти выражения TRUE.

Личные советы: Collations в VFP никогда не были достаточно надежными. Я предлагаю вам не использовать сортировки и придерживаться стандартного «MACHINE». Если вы будете использовать сортировки, тогда имейте в виду сначала проверить это, когда вы испытываете что-то очень неожиданное в отношении персональных данных. Я видел и демонстрировал, что во многих случаях это терпит неудачу, но затем я переставал пытаться использовать его до версии VFP9, теперь он может быть последовательным, я действительно не знаю.

Учитывая, что мы рассматривали случаи неравенства со строками, сложным является случай равенства. В VFP в основном две настройки влияют на сравнение:

  1. SET EXACT (значение по умолчанию выключено и используется для сравнения с обычным сравнением - те, за исключением SQL)
  2. SET ANSI (по умолчанию OFF и сравнение эффектов только в SQL. SET EXACT не влияет на сравнения, сделанные в SQL-запросах.

Если SET EXACT OFF, прочитайте сравнение как «строка в начале справа со строкой слева»? Они сравниваются с длиной правой строки.

? "Bobby" = "B" && Bobby starts with B, so TRUE
? "Bobby" = "Bob" && Bobby starts with Bob, so TRUE
? "Bobby" = "Bob " && Bobby starts with Bob but there is a trailing space there, FALSE
? "Bobby" = "bob" && would be true with collation set to GENERAL

Обратите внимание, что при регулярном сравнении «Bobby» = «B» имеет значение TRUE, но «B» = «Bobby» - FALSE. Другими словами, место операндов важно.

С SET EXACT ON строки должны совпадать полностью, но их конечные пробелы игнорируются (мы игнорируем здесь set collate, который также будет нечувствителен к регистру):

? "BOBBY" = "BOB" && FALSE 
? "BOBBY" = "BOBBY" && TRUE
? "BOBBY" = "BOBBY     " && TRUE 
? "BOBBY     " = "BOBBY" && TRUE

Теперь с командами SQL SET EXACT не действует, и он будет вести себя как SET EXACT OFF.

Select * from Customers where Country = 'U'

Выбрали бы клиентов из США, Великобритании в любую страну, начиная с «U».

Однако в SQL по определению изменение порядка операндов должно давать тот же результат. Таким образом:

Select * from Customers where 'U' = Country

также будет работать одинаково (обратите внимание на отличие от команд, отличных от SQL).

Если вы хотите указать точное соответствие, один из вариантов - включить ANSI:

SET ANSI ON
Select * from Customers where Country = 'USA'

возвращает всех этих клиентов из США. Обратите внимание, что конечные пробелы в поле страны OR в правильном выражении игнорируются. Было бы неважно, сколько у вас с обеих сторон. Вы получаете сравнение, как если бы это было сделано, как: RTRIM (Страна) = RTRIM ('США').

Хотя он не упоминается в операторах в VFP, оператор SQL LIKE. Когда вы используете LIKE, вы получаете точное сравнение совпадений, независимо от установки SET ANSI (используя силы LIKE и неявный случай ANSI ON - в конце концов, это ANSI-оператор). Однако будьте осторожны, есть небольшая разница в поведении. Он не будет игнорировать конечные пробелы, если общий размер с прицепами не меньше или меньше размера поля. Например, если поле Country равно C (10), тогда будет работать Country = 'USA' или Country = 'USA__', но Country = 'USA___________' потерпит неудачу ( подчеркивание обозначает пробел, а последний имеет более 7 конечных пробелов).

Наконец, мы доходим до последнего оператора ==. Это означает, что он ровно равен и позволяет использовать его со строками. Одно из преимуществ заключается в том, что, используя ==, вы всегда подразумеваете, что хотите точное совпадение, независимо от настроек SET EXACT или SET ANSI. Однако будьте осторожны, его поведение отличается, когда оно является командой SQL или обычной командой nonSQL.

С SQL:

Select * from Customers where Country == 'USA'

независимо от настроек ANSI и EXACT, мы хотим, чтобы все клиенты только из США. Промежуточные пробелы с обеих сторон игнорируются.

С не-SQL:

? m.lcString1 == m.lcString2

было бы справедливо только в том случае, если они точно такие же, относительно их обсадной колонны и длины (конечные пробелы НЕ игнорируются). Это не выполняется из настроек SET ANSI, EXACT или COLLATE.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow