Ricerca…


Osservazioni

In VFP, gli operatori sono raggruppati in quelli:

  • Operatori numerici
  • Operatori logici
  • Operatori di caratteri
  • Operatori di data e ora
  • Operatori relazionali

Inoltre ci sono operatori, implementati come funzioni (come operazioni bit a bit, confronto tra oggetti ...).

Esamineremo ciascuno con l'esempio.

Operatori numerici

Gli operatori numerici sono i più semplici e quasi gli stessi di altre lingue.

  • +, -, * e /. Addizioni, sottrazioni, moltiplicatori e operatori di divisione (in VFP non esiste una divisione intera, è possibile convertire un risultato in intero con le funzioni INT (), CEILING () e FLOOR ()).
  • Operatore% modulo.
  • ^ e **. Potere dell'operatore / i. Entrambi fanno la stessa cosa.
  • (). Raggruppamento di operatori.
  • Gli operatori hanno la precedenza. L'ordine è:
   ( )
   ^ (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. 

Operatori logici

Gli operatori logici in VFP, nel loro ordine di precedenza sono:

Operatore Descrizione
() Parentesi, gruppi di espressioni
NON,! Negare logicamente l'espressione. NON o! non ha differenza.
E Logicamente E le espressioni
O Logicamente O le espressioni
<>,! =, # Controlla la disuguaglianza. Così come OR esclusivo OR - XOR

Storicamente, NOT, AND, OR sono scritti come .NOT., .AND., .OR. Puoi ancora usarli se vuoi, ma AND, OR, NOT è più semplice e più pulito.

Per falso e vero, devi usare. e T. letterali rispettivamente. Non puoi scegliere di usare F e T invece.

* 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

In VFP, le espressioni logiche vengono valutate in una scorciatoia. Cioè, se la prima parte del controllo soddisfa l'intero risultato, il resto dell'espressione non viene neppure interpretato. Segue un esempio:

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

Una trappola che cattura i neofiti è che, a volte potresti aver bisogno di più controlli, ad esempio in una query SQL, che sono collegati con gli operatori AND, OR. Quando ce ne sono molti, uno potrebbe ignorare il fatto che gli operatori hanno una precedenza (in ordine (), NOT, AND, OR) e pensano che l'interpretazione sia fatta da sinistra a destra in una catena. Considera un campione:

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

qual è l'intenzione di questa query? Se lo rendiamo esplicito usando le parentesi di raggruppamento, dice:

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

semplificato sembra "firstExpression" OR (sconto> 5). Qualunque fosse l'intenzione, a causa di questo OR avrebbe selezionato:

tutte le righe che hanno (sconto> 5) - e anche quelle in cui è un cliente con oltre 5000 debiti.

Probabilmente l'intenzione era "dammi quelli dove NON è un cliente E (l'addebito è superiore a 5000 O lo sconto è superiore a 5)". Sarebbe chiaro fin dall'inizio se abbiamo usato le parentesi:

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

Si può usare ma non vale la pena di avere parentesi per l'operatore NOT iniziale, quando il suo operando è una singola espressione sufficientemente leggibile con la sua precedenza -! IsCustomer è chiaramente letto come (NOT isCustomer).

Operatori di caratteri

Ci sono solo 4 operatori di caratteri, nel loro ordine di precedenza:

Operatore Descrizione
() Parentesi per raggruppamento. Nota: la documentazione VFP, che ho, manca questa. Senza questo, l'operatore è quasi sempre inutile.
+ Concatena (unisce) stringhe affiancate.
- Concatena le stringhe spostando gli spazi finali dalla stringa sinistra alla fine della stringa destra.
$ Controlla se la prima stringa è contenuta in secondo.

+ è il più semplice ed è anche usato per concatenare stringhe in molte altre lingue.

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

? m.firstName + " " + m.lastName

Uscite: John Smith

- è un po 'complicato e non molto conosciuto. Prende spazi finali dalla stringa di sinistra, aggiunge quegli spazi alla stringa sulla destra. Supponiamo di avere una tabella con il nome e il cognome e ognuno di essi è di 20 caratteri. Vogliamo concatenare il nome e il cognome per creare un nome completo e vogliamo anche correggere la dimensione risultante (in questo caso 20 + 20 + 1 spazio = 41). Facciamolo avere anche una colonna di secondo nome e vogliamo che il nome completo assomigli a "lastName, firstName middleName_______". È più facile farlo usando l'operatore, ma si deve notare il trucco di usare le parentesi qui per il raggruppamento in modo da ottenere esattamente ciò che vogliamo:

* 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

E l'uscita è così:

nome di battesimo midName cognome nome e cognome
Cetin Basoz Basoz, Cetin
John M fabbro Smith, John M
John F Kennedy Kennedy, John F
Tom Hanks Hanks, Tom

Nella colonna fullName tutti gli spazi finali sono spinti fino alla fine. Se controlli la struttura, la colonna fullName ha una larghezza di 63 caratteri (3 * 20 + 3 caratteri che abbiamo aggiunto).

Nota l'importanza del raggruppamento delle parentesi (prova a rimuovere le parentesi o a organizzare in modo diverso).

Anche se l'operatore potrebbe essere tentato di utilizzare in questi casi, c'è un altro lato della medaglia. Questo operatore è specifico per VFP e quindi SQL non è portatile. È possibile ottenere lo stesso risultato con questo SQL ANSI compatibile:

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

L'ultimo operatore è $. Controlla semplicemente se la stringa sinistra fa parte della stringa corretta.

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.

Importante: in VFP, sebbene sia possibile scrivere il codice in ogni caso (superiore, inferiore o misto), le stringhe sono sempre case sensitive. Ad esempio: "Smith" e "fabbro" sono due valori distinti. O nel tuo tavolo se c'è una colonna di paese, non troverai "USA" se la cerchi con "usa". Lo stesso vale per $ operatore, "GE" $ "Germania" è falso.

Nota personale: Sebbene possa piacerti $ per la sua semplicità e potresti trovarlo spesso utilizzato nei codici sorgente Microsoft, IMHO ha un valore molto basso. Pensando a molte molte migliaia di righe che ho scritto nella mia carriera, penso che ne troverei molto poche nel mio codice. Quasi sempre esiste un'alternativa migliore (specialmente quando l'operando a sinistra non è un singolo carattere e \ o la distinzione tra maiuscole e minuscole è importante).

Operatori di data e ora

Esistono fondamentalmente due operatori per data, valori datetime. + e - sono sovraccaricati (probabilmente un termine C) per fare la matematica data / data / ora:

Operatore Descrizione
+ Aggiunge giorni (data) o secondi (datetime) a un valore data / datetime.
- Ottiene la differenza di due valori data / datetime. Sottrae i giorni (data) o secondi (datetime) dai valori datetime.

+ è più facile. Ha due operandi, uno è un valore data o datetime e l'altro è un valore numerico (sebbene sia possibile utilizzare qualsiasi valore numerico, è un numero intero per tutti gli scopi pratici).

Quando uno degli operandi è una data, l'operando numerico viene considerato come "giorno":

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

Quando uno degli operandi è un datetime, l'operando numerico viene considerato come "secondo":

Ci sono 24 * 60 * 60 = 86400 secondi in un giorno

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

Aggiungi 4 ore e 15 minuti a Gen 1, 2016 2:20 PM

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

Uscite venerdì 1 gennaio 2016, 18:35:00.

Con una semplice stampa utilizzando?, Ciò che vedi sullo schermo dipende dalle impostazioni della data. Ad esempio, se non hai cambiato nulla, le impostazioni della data sono in stile americano (MDY), il formato 12 ore (AM / PM) e il secolo sono visualizzati solo con le ultime 2 cifre.

C'è un simbolo speciale ^ per la data e il periodo di tempo che obbliga una stringa ad essere interpretata "rigorosamente" come yyyy / MM / gg [HH: mm: ss | hh: mm: ss tt]. Pertanto ^ potrebbe essere considerato anche come operatore data / data / ora. Ad esempio, considera alcuni dati in arrivo da una fonte in un formato come 201610082230 (aaaaMMggHHmm). Per ottenere quel valore come un Data / ora valido:

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

Uscite (a seconda dell'impostazione della data estesa del sistema):

Sabato 8 ottobre 2016, ore 22.30

- è usato per la sottrazione. I suoi operandi sono entrambi valori data / datetime O uno è una data / datetime e l'altro è un valore numerico.

Iniziamo con la data / data e gli operandi numerici più semplici (come con l'operatore +):

Quando uno degli operandi è una data, l'operando numerico viene considerato come "giorno":

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

Quando uno degli operandi è un datetime, l'operando numerico viene considerato come "secondo":

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

Ricevi 1 ora e 30 minuti fa da "ora":

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

La seconda forma è quella di ottenere la differenza tra due valori data / datetime. Gli operandi sono sia di data che di data / ora, non è possibile utilizzare contemporaneamente data e data / ora (eseguire la conversione del tipo secondo necessità, VFP non lo fa per te). Le regole sono come in + e -, gli operandi sono la data quindi la differenza è in giorni , gli operandi sono datetime, quindi la differenza è in secondi .

Quanti giorni a capodanno (per l'anno 2016)?

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

Quanti secondi sono rimasti a mezzanotte?

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

Nell'ultimo campione abbiamo usato una funzione Date / Datetime, DTOT - DateToTime per ottenere il valore di mezzanotte di domani. Sono disponibili molte funzioni di data / datetime utili, le abbiamo saltate tutte perché tecnicamente non sono considerate operatori (sebbene operino su data / datet :) :) Lo stesso vale per gli altri operatori.

La sottrazione data / datetime è firmata . Cioè se si utilizza la data / data / ora più piccola come primo operando, il risultato sarebbe negativo. È possibile utilizzare la funzione abs () se è necessario ottenere un risultato positivo indipendentemente dall'ordine di data / data / ora.

Operatori relazionali

Di tutti gli operatori, gli operatori relazionali sono i più complessi, per questo li abbiamo lasciati alla fine.

Gli operatori relazionali sono anche noti come operatori di confronto, sono usati per confrontare le cose.

Il risultato di confronto è booleano falso o vero.

È interessante notare che, se lo si controlla in VFP, è possibile vedere solo una breve lista di operazioni e qualche altra riga come se fosse tutto su quegli operatori.

Bene, la complessità deriva dal fatto che, operano su qualsiasi tipo sia esso numerico, data, datetime, logico o stringa, e persino sugli oggetti. Inoltre, il comportamento potrebbe sembrare imbarazzante, non ottieni ciò che ti aspetti se non sai quali effetti hanno i risultati.

Iniziamo con un elenco di operatori relazionali:

Operatore Descrizione La maggior parte dei campioni di base
> Più grande di ? 1> 2 && .F.
< Meno di ? 1 <2 && .T.
> = Maggiore o uguale a ? 1> = 2 && .F.
<= Minore o uguale a ? 1 <= 2 && .T.
= Uguale a ? 1 = 1 && .T.
== È esattamente uguale a (ha senso per le stringhe) ? '1' = '1' && .T.
! =, #, <> Non uguale a (tutti e 3 gli operatori agiscono allo stesso modo, scegli il tuo preferito) ? 1! = 1 && .F.

Sebbene sia possibile utilizzarli con tutti i tipi di dati, dovrebbe esserci una compatibilità di tipo tra gli operandi. Ad esempio, si otterrebbe un errore se si tenta di confrontare una data con un numero intero.

Data e data / ora possono essere confrontati, anche se sono tipi diversi, VFP esegue la conversione implicitamente per te.

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

Quando gli operandi sono numerici, tutti questi operatori sono semplici e diretti, funzionano come dovrebbero fare nell'espressione matematica.

Con gli operandi logici, .F. è considerato inferiore a .T.

Con gli oggetti ciò che stiamo confrontando è il riferimento dell'oggetto in memoria. Quindi il confronto più utilizzato è determinare se due variabili oggetto puntano allo stesso oggetto. vale a dire:

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

Il confronto del tipo di dati di carattere, noto anche come confronto delle stringhe, è il più confuso in VFP. Non funziona come in altri linguaggi e / o database e unico per VFP (e forse per qualche altro linguaggio xBase).

Molti anni fa, ho persino visto alcuni membri veramente avanzati nella comunità che non erano ancora a conoscenza di come questi operatori lavorassero in VFP. Quindi è abbastanza comprensibile leggere sfumature potrebbe confondere facilmente i neofiti.

Il confronto è fondamentalmente sull'essere uguali o meno. Se non sono uguali, allora potremmo pensare agli operatori>, <,> =, <=, giusto? Con le stringhe è confuso quando due stringhe sono considerate uguali .

Importante: le stringhe VFP sono sensibili al maiuscolo / minuscolo. 'A' e 'a' sono due stringhe distinte. Questo non è il caso di molti database in cui l'impostazione predefinita è l'utilizzo di regole di confronto senza distinzione tra maiuscole e minuscole. Ad esempio in postgreSQL o MS SQL Server su una tabella creata con regole di confronto senza distinzione tra maiuscole e minuscole (CI):

select * from myTable where Country = 'TURKEY'

select * from myTable where Country = 'Turkey'

darebbe lo stesso risultato. In VFP, però, si ottengono solo quelli in cui sono presenti corrispondenze. Tuttavia VFP ha un supporto per le regole di confronto e rende il confronto tra maiuscole e minuscole. (Non fidarti, vedi sotto)

  • Se due stringhe non sono uguali, fin qui tutto bene, a condizione che non siano stati modificati i valori predefiniti, essi vengono confrontati in base ai loro valori ASCII .

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

L'impostazione predefinita per le regole di confronto è 'macchina' e questo è ciò che ottieni. Quando modifichi le regole di confronto in qualcos'altro, ottieni il confronto in base al criterio di ordinamento di tale raccolta. Con l'impostazione di regole di confronto diversa dalla macchina predefinita , si sta anche insinuando un caso insensibile al confronto (NON fidarsi di questo per l'uguaglianza):

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

Ora tutte queste espressioni sono VERE.

Consiglio personale : le regole di confronto in VFP non sono mai state sufficientemente affidabili. Ti suggerisco di non utilizzare le regole di confronto e di utilizzare "MACCHINA" di default. Se vuoi utilizzare le regole di confronto, tieni a mente di controllarlo prima quando riscontri qualcosa di molto inaspettato riguardo ai dati dei personaggi. Ho visto e dimostrato che fallisce in molti casi, ma poi ho smesso di provare a usarlo molto prima della versione VFP9, potrebbe essere coerente ora, davvero non lo so.

Considerando che abbiamo coperto casi di disuguaglianza con stringhe, il difficile è il caso di uguaglianza. In VFP fondamentalmente due impostazioni influenzano il confronto:

  1. SET EXACT (L'impostazione predefinita è OFF ed effettua il confronto regolare - quelli ad eccezione di SQL)
  2. SET ANSI (l'impostazione predefinita è OFF e confronti degli effetti solo in SQL SET EXACT non ha alcun effetto sui confronti effettuati con le query SQL.

Con SET EXACT OFF, leggi il confronto come "la stringa inizia a destra con la stringa a sinistra"? Vengono confrontati con la lunghezza della corda corretta.

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

Si noti che con il confronto regolare, "Bobby" = "B" è VERO, ma "B" = "Bobby" è FALSE. In altre parole, il ruolo degli operandi è importante.

Con SET EXACT ON le stringhe devono combaciare completamente ma i loro spazi finali vengono ignorati (stiamo ignorando la fascicolazione di set qui che farebbe anche insensibilità al maiuscolo / minuscolo):

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

Ora, con i comandi SQL SET EXACT non ha alcun effetto e si comporterebbe come fa SET EXACT OFF.

Select * from Customers where Country = 'U'

Selezionerei i clienti dagli Stati Uniti, Regno Unito, qualsiasi nazione che inizi con "U".

In SQL, tuttavia, per definizione la modifica dell'ordine degli operandi dovrebbe produrre lo stesso risultato. Così:

Select * from Customers where 'U' = Country

funzionerebbe allo stesso modo (notare la differenza dai comandi non SQL).

Quando vuoi implicare corrispondenze esatte, un'opzione è di attivare ANSI:

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

restituisce tutti quei clienti dagli Stati Uniti. Nota che gli spazi finali nel campo paese OR sull'espressione destra vengono ignorati. Non importa quanti tiri da entrambe le parti hai. Si ottiene il confronto come se fosse fatto come: RTRIM (Paese) = RTRIM ('USA').

Sebbene non sia menzionato negli operatori in VFP, un operatore SQL è LIKE. Quando si utilizza LIKE, si ottiene un confronto di corrispondenza esatto indipendentemente dall'impostazione SET ANSI (utilizzando le forze LIKE e il caso ANSI ON implicito, dopotutto è un operatore ANSI). Tuttavia, attenzione c'è una leggera differenza di comportamento. Non ignorerebbe gli spazi finali, a meno che la dimensione totale con i rimorchi sia uguale o inferiore alla dimensione del campo. Ad esempio se il campo Paese è C (10), quindi Paese = 'USA' o Paese = 'USA__' funzionerebbe, ma Paese = 'USA___________' fallirebbe (i trattini bassi denotano uno spazio e l'ultimo ha più di 7 spazi finali).

Finalmente siamo fino all'ultimo operatore, ==. Ciò significa esattamente uguale e fa uso con le stringhe. Un vantaggio è che, usando ==, si intende sempre che si desidera una corrispondenza esatta indipendentemente dalle impostazioni SET EXACT o SET ANSI. Tuttavia, fate attenzione di nuovo, il suo comportamento è diverso quando si tratta di un comando SQL o un comando regolare non SQL.

Con SQL:

Select * from Customers where Country == 'USA'

qualunque siano le impostazioni ANSI ed EXACT, vogliamo tutti i clienti dagli Stati Uniti. Gli spazi finali su entrambi i lati vengono ignorati.

Con non-SQL:

? m.lcString1 == m.lcString2

sarebbe vero solo se sono esattamente gli stessi, per quanto riguarda l'involucro e la lunghezza (gli spazi finali NON sono ignorati). Non viene effettuato dalle impostazioni SET ANSI, EXACT o COLLATE.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow