2
votes

Comment détecter quelle unité quelqu'un tape dans un champ de saisie

Je veux pouvoir détecter l'unité que quelqu'un tape dans un champ de saisie de texte libre. Par exemple, s'ils saisissent 100 kg , je veux détecter qu'il s'agit du poids . S'ils saisissent 100 litres , il devrait détecter volume et ainsi de suite. Je veux que cela fonctionne pour différents styles d'entrée. Par exemple, 100 kg et 100 kg doivent tous deux être détectés comme poids.

C'est ainsi que je l'ai construit actuellement. Cela fonctionne pour des exemples simples, mais cela pose quelques problèmes:

import React from 'react';
import { render } from 'react-dom';
import PropTypes from 'prop-types';
import { observer } from "mobx-react";


@observer
export default class DemoComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            inputValue: "",
            unit: "no unit detected",
        }
    }

    updateInputValue(e) {
        let unit = this.detectUnit(e.target.value);
        if(unit) {
            this.setState({unit: unit,inputValue: e.target.value});
        } else {
            this.setState({unit: "no unit detected",inputValue: 
            e.target.value})
        }
    }

    detectUnit(string) {
        let currentUnit = false;
        let cleanedString = string.toLowerCase();
        for (let unit in units) {
            if (units.hasOwnProperty(unit)) {
                // do stuff
                for(let i = 0; i < units[unit].length ; i++) {
                    if(cleanedString.includes(units[unit][i])) {
                        currentUnit = unit;
                        break;
                    }
                }
            }
        }
        console.log(currentUnit)
        return currentUnit;        
    }
    render() {
        return (
            <div id="testID">
                <h1 className="democss">{this.props.title}</h1>
            <div className="container">
                <input value={this.state.inputValue} onChange={(e) => 
                this.updateInputValue(e)} />
                <h2 className="unit">{this.state.unit}</h2>
            </div>
            </div>
        );
    }
}

const units = {
    velocity: ["m/s","km/h","meter/s","m/sekund", "meter/sekund",],
    weight: ["kg","kilogram","kilo gram","kgram","k gram","kilo","k"],
    volume: ["liter",], //add "l" later
}

Si je tape randomliter , il le détectera comme volume car la chaîne litre existe. Comment résoudre ce problème afin qu'il vérifie uniquement la correspondance exacte tout en étant capable d'accepter plusieurs styles d'entrée tels que

100 kg 100 kg kg 100

et les détecter tous comme poids? Est-ce quelque chose que je pourrais utiliser regex? Le point clé est qu'ils peuvent entrer une valeur et une unité librement, et j'ai besoin de détecter la valeur et l'unité.


2 commentaires

Vous utilisez includes () . Vous devriez probablement correspondre exactement à la chaîne à la place. Ou peut-être faire une correspondance de mots.


Vous n'avez pas vraiment besoin de if (units.hasOwnProperty (unit)) si vous utilisez for..in . Vous pouvez supposer que chaque propriété de units apparaît dans l'itération.


4 Réponses :


2
votes

MODIFIER: La réponse de Mad est meilleure. Si vous compariez simplement "randomLiter" à "litre", ma réponse ci-dessous serait meilleure, mais vous comparez "100 randomLiters" à "litre", ce qui rend l'approche de Mad d'utilisation de RegEx plus applicable. Je vais simplement laisser la réponse ci-dessous pour la postérité.

Au lieu de vérifier si chaque élément du tableau unit existe dans cleaningString , faites-le dans l'autre sens, et vérifiez si cleaningString existe dans le tableau unit :

Autrement dit, au lieu de ceci:

units[unit].includes(cleanedString)
// ...is the same as
['liter'].includes('randomliter')
// ...which will return 'false'.

... faites ceci: p >

cleanedString.includes(units[unit][i]))
// ...is the same as
'randomliter'.includes('liter')
// ...which will return 'true'

Explication:

  • units [unit] est un tableau de chaînes.
  • units [unit] [i] est une chaîne.
  • cleaningString est une chaîne.

{stringA} .includes ({stringB}) vérifie si stringB est une sous-chaîne de stringA

for (let unit in units) {
    if(units[unit].includes(cleanedString)){
        currentUnit = unit
        break
    }
}

{array} .includes ({stringB}) vérifie si stringB correspond exactement à l'un des valeurs dans array.

for (let unit in units) {
    if (units.hasOwnProperty(unit)) {
        // do stuff
        for(let i = 0; i < units[unit].length ; i++) {
            if(cleanedString.includes(units[unit][i])) {
                currentUnit = unit;
                break;
            }
        }
    }
}

0 commentaires

3
votes

Utilisez match avec une expression régulière au lieu de includes .

Ce qui suit devrait faire ce que vous voulez pour l'exemple de kg.

regex = '^[0-9]*\s*kg\s*[0-9]*$'
cleanedString.match(regex)

Voir ici pour une démonstration / explication de l'expression régulière. p>


0 commentaires

-1
votes

Essayez ceci:

function detectUnit(string) {
  const unit = string.replace(/\d+/g,'').trim().toLowerCase();
  switch(true) {
    case units.velocity.includes(unit):
        return "velocity";
    case units.weight.includes(unit):
        return "weight";
    case units.volume.includes(unit):
        return "volume";
    default:
        return "default";
  }
}


1 commentaires

Ce n'est pas très SEC. Au lieu de coder en dur un cas pour chaque type d'unité, vous devriez utiliser une sorte d'itération.



0
votes

La fonction suivante retournera le type exact:

function getUnit(inputValue){
  const units = {
    velocity: ["m/s", "km/h", "meter/s", "m/sekund", "meter/sekund",],
    weight: ["kg", "kilogram", "kilo gram", "kgram", "k gram", "kilo", "k"],
    volume: ["liter", "l"]
  }

  const result = Object.entries(units).find(([name, typos]) => typos.some(typo => inputValue.includes(typo)))

  return result ? result[0] : null
}

console.log(getUnit('450 kg'))
console.log(getUnit('4 l'))
console.log(getUnit('50 meter/s'))
console.log(getUnit('850 rfeh'))
console.log(getUnit('4.56 kgram'))
console.log(getUnit('756 liter'))
console.log(getUnit('758 meter/sekund'))

Cette fonction itère sur chaque type d'unité dans votre tableau puis sur toutes les chaînes différentes, si l'une correspond, elle renvoie l'objet entier.

Exemple de travail:

const units = {
    velocity: ["m/s", "km/h", "meter/s", "m/sekund", "meter/sekund",],
    weight: ["kg", "kilogram", "kilo gram", "kgram", "k gram", "kilo", "k"],
    volume: ["liter", "l"]
}

Object.entries(units).find(([name, typos]) => typos.some(typo => inputValue.includes(typo)))


0 commentaires