サーチ…


備考

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の論理演算子の優先順位は、次のとおりです。

オペレーター説明
() 括弧、グループ式
そうではありません! 式を論理的に否定します。ないまたは!違いはありません。
そして論理的にAND式
または論理式OR
<>、!=、# 不平等をチェックする。論理的な排他的論理和 - 排他的論理和

歴史的に、NOT、AND、ORは、NOT、.AND、.ORとして書かれています。あなたが好きなら、あなたはまだそれを使うことができますが、AND、OR NOTは簡単で清潔です。

falseとtrueの場合は、.Fを使用する必要があります。および.T。リテラルです。代わりに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.

初心者を惹きつけている落とし穴の1つは、時には、AND、OR演算子に接続されたSQLクエリーで、複数のチェックが必要な場合があるということです。それらの多くがあるとき、演算子が優先順位(順序()、NOT、AND、OR)を持っているという事実を無視し、解釈がチェーン内で左から右に行われると考えるかもしれません。サンプルを考えてみましょう:

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

このクエリの意図は何ですか?グループ化カッコを使用して明示的にすると、次のようになります。

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

簡略化して "firstExpression" OR(割引> 5)のように見えます。意図が何であったとしても、このORのために以下を選択します:

(割引> 5)を持つ行と、5,000デビットを超える顧客である行も含まれます。

おそらく、その意図は「顧客ではない場所に(借方は5000以上の割引が5以上のものを)私に渡す」というものでした。最初から括弧を使用しているかどうかはわかります。

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

最初のNOT演算子に括弧を付けることはできますが、そのオペランドが単一の式であり、その優先順位が十分であるときに括弧を付けることはできますが、価値はありません - !isCustomerは(isCustomerではない)として明確に読み取られます。

文字演算子

優先順位は4文字の演算子しかありません。

オペレーター説明
() グループ化のかっこ。注:私が持っているVFPドキュメントは、これを見逃しています。これがなければ、 - 演算子はほとんど常に役に立たない。
+ 文字列を並べて連結します。
- 末尾のスペースを左の文字列から右の文字列の最後に移動して文字列を連結します。
$ 最初の文字列が2番目に含まれているかどうかをチェックします。

+は最もシンプルで、他の多くの言語で文字列を連結するのにも使用されます。

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

? m.firstName + " " + m.lastName

アウトプット:John Smith

- 少しトリッキーで、広く知られていません。左の文字列から末尾のスペースを取り、そのスペースを右の文字列に追加します。姓と名字のテーブルがあり、それぞれが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

そして出力は次のようなものです:

ファーストネームミッドナ苗字フルネーム
Cetin Basoz Basoz、Cetin
ジョン M スミススミス、ジョン・M
ジョン F ケネディケネディ、ジョンF
トムハンクストム・ハンクス

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では、大文字、小文字、または混在のいずれの場合でもコードを記述できますが、文字列は常に大文字と小文字が区別されます。たとえば、「Smith」と「smith」は2つの異なる値です。あなたのテーブルでは、国の列がある場合は、それを 'usa'で検索すると 'USA'は見つかりません。 $演算子でも同じですが、 "GE" $ "Germany"はfalseです。

個人的な注意:あなたは単純さのために$が好きかもしれませんが、それはMicrosoftのソースコードで頻繁に使用されることがありますが、IMHOはそれほど価値がありません。私がキャリアに書いた多くの何千もの行について考えてみると、私は自分のコードでそれが起こることはほとんどないと思う。ほとんどの場合、より良い選択肢があります(特に左のオペランドが単一の文字ではなく、大文字と小文字の区別に問題がある場合)。

日時演算子

基本的に、日付、日時の値には2つの演算子があります。 +と - は日付/日時演算を行うためにオーバーロードされます(おそらくCの項):

オペレーター説明
+ 日付/日時の値に日(日付)または秒(日時)を追加します。
- 2つの日付/日時の値の差を取得します。 datetime値から日(日付)または秒(日時)を引く。

+は簡単です。これは2つのオペランドを持ちます.1つは日付または日時の値で、もう1つは数値です(数値を使用することもできますが、すべての実用的な目的で整数です)。

オペランドの1つが日付の場合、数値オペランドは「日」と見なされます。

? 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.

オペランドの1つがdatetimeの場合、数値オペランドは「second」とみなされます。

1日に24 * 60 * 60 = 86400秒があります

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

2016年1月1日までに4時間15分追加

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

出力2016年1月1日(金)、午後6時35分

?を使用した簡単な印刷では、画面に表示される内容は日付設定に依存します。たとえば、何も変更していない場合、日付設定はアメリカンスタイル(MDY)、12時間形式(AM / PM)、および世紀は最後の2桁のみで表示されます。

dateとdatetimeには、文字列を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')

出力(システムの長い日付設定に応じて):

2016年10月8日(土)、10:30 PM

- は減算に使用されます。そのオペランドは、日付/時刻の両方の値か、日付/時刻と数値の両方のどちらかです。

まずは、より簡単な日付/日時と数値オペランド(+演算子など)から始めましょう:

オペランドの1つが日付の場合、数値オペランドは「日」と見なされます。

? 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.

オペランドの1つがdatetimeの場合、数値オペランドは「second」とみなされます。

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

"now"から1時間30分前に取得:

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

2つ目の形式は、2つの日付/日時の値の差を取得することです。オペランドは日付または日時の両方であり、日付と日時を同時に使用することはできません(必要に応じて型変換を行いますが、VFPはそれを行いません)。ルールは+と - のようになり、オペランドは日付で、次に差分は日で 、オペランドは日時で、その後の差はです。

新年の前夜(2016年)の日数は何日ですか?

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

深夜まで何秒残っていますか?

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

最後のサンプルでは、​​明日の真夜中値を取得するためのDate / Datetime関数DTOT - DateToTimeを使用しました。便利な日付/日時関数は数多くありますが、技術的には演算子とはみなされないため、これらはすべてスキップされています(date / datetimeで動作しますが)。他の演算子でも同様です。

日付/日時の減算が署名されています。つまり、より小さいdate / datetimeを最初のオペランドとして使用すると、結果は負の値になります。日付/日付の順序に関係なく肯定的な結果を得る必要がある場合は、abs()関数を使用することができます。

関係演算子

すべての演算子のうち、関係演算子は最も複雑なものであり、そのため私たちはそれらを最後まで残しました。

関係演算子は比較演算子とも呼ばれ、物事を比較するために使用されます。

比較結果は真偽または真です。

興味深いことに、VFPのヘルプでチェックすると、短いリスト操作と、あたかもそれらの演算子に関するすべての行が表示されます。

まあ、複雑さは、数字、日付、日時、論理または文字列、さらにはオブジェクト上でさえも、 どんな型でも動作するという事実から来ています。さらに、行動は厄介なように見えるかもしれません。結果にどのような影響があるか分からない限り 、あなたは期待したことを得られません。

関係演算子のリストから始めましょう:

オペレーター説明 MOST基本サンプル
> より大きい ? 1> 2 &&。
< 未満 ? 1 <2 &&。
> = 以上 ? 1> = 2 &&。
<= 以下 ? 1 <= 2 &&。
= に等しい ? 1 = 1 &&。
== 正確に等しい(文字列には意味をなさない) ? '1' = '1' && .T。
!=、#、<> 同じではない(3人のオペレータはすべて同じように行動し、お気に入りを選択する) ? 1!= 1 && .F。

これらをすべてのデータ型で使用できますが、オペランド間に型の互換性があるはずです。たとえば、DateとIntegerを比較しようとすると、エラーが発生します。

DateとDatetimeは比較することができますが、それらは異なる型ですが、VFPは暗黙的に変換を行います。

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

オペランドが数値の場合、これらの演算子はすべて単純で簡単ですが、数学式の場合と同じように動作します。

論理オペランドでは、.F。 .Tよりも小さいとみなされる。

私たちが比較しているオブジェクトでは、メモリ内のオブジェクトの参照です。したがって、最もよく使用される比較は、2つのオブジェクト変数が同じオブジェクトを指しているかどうかを判断することです。すなわち:

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?文字列では、 2つの文字列が等しいとみなされると混乱します

重要: VFP文字列は大文字と小文字が区別されます。 'A'と 'a'は2つの異なる文字列です。これは、大文字と小文字を区別しない照合をデフォルトで使用する多くのデータベースでは当てはまりません。たとえば、大文字小文字を区別しない(CI)照合で作成されたテーブルのpostgreSQLまたはMS SQL Serverの場合:

select * from myTable where Country = 'TURKEY'

select * from myTable where Country = 'Turkey'

同じ結果が得られます。 VFPでは、大文字と小文字が一致するものだけを取得します。ただし、VFP toには照合がサポートされており、大文字と小文字を区別しない比較が行われます。 (信頼しないでください、下を参照してください)

  • 2つの文字列が等しくない場合は、 デフォルト 値を 変更しなかった場合は ASCII値に基づいて比較されます

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

照合のデフォルトは 'machine'で、これがあなたのものです。照合を他のものに変更すると、その照合のソート順に基づいて照合が行われます。デフォルトのマシン以外の照合設定では、比較で大文字と小文字を区別しないことを暗示しています(同等であるとは信じてはいけません):

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

これらの式はすべて真です。

個人的なアドバイス:VFPの照合は決して信頼できるものではありません。私は照合を使用せず、デフォルトの 'MACHINE'に固執することをお勧めします。照合を使用する場合は、文字データに関して予期しないことが起きたときに照合を最初にチェックすることを忘れないでください。私はそれが多くの場合に失敗することを見て、実証しましたが、VFP9より前に使用しようとしなくなりました。これは一貫しているかもしれません。

文字列で不等式を扱う場合を考えてみると、やりにくいのは等式です。 VFPでは、基本的に2つの設定が比較に影響します。

  1. SET EXACT(デフォルトはOFFで、通常の比較 - 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を指定すると、文字列は完全に一致する必要がありますが、後続のスペースは無視されます(ここでは、大文字と小文字を区別しません)。

? "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( 'USA')のように行われます。

VFPの演算子には記述されていませんが、SQL 演算子はLIKEです。 LIKEを使用すると、SET ANSI設定に関係なく完全一致比較が得られます(LIKEの力と暗黙的なANSI ONの場合を使用 - ANSI演算子の後にあります)。ただし、動作には若干の違いがあります。予告編の合計サイズがフィールドサイズ以下でない限り 、後続のスペースは無視されません。たとえば、CountryフィールドがC(10)の場合、Country = 'USA'またはCountry = 'USA__'は機能しますが、Country = 'USA__________'は失敗します( アンダースコアはスペースを示し、最後はスペースが7つ続きます)。

最後に、最後の演算子==までです。それはまったく同じことを意味し、文字列で使用することを意味します。利点の1つは、==を使用すると 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