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é.
4 Réponses :
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
unitexiste danscleaningString, faites-le dans l'autre sens, et vérifiez sicleaningStringexiste dans le tableauunit: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.cleaningStringest une chaîne.
{stringA} .includes ({stringB})vérifie sistringBest une sous-chaîne destringAfor (let unit in units) { if(units[unit].includes(cleanedString)){ currentUnit = unit break } }
{array} .includes ({stringB})vérifie sistringBcorrespond exactement à l'un des valeurs dansarray.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; } } } }
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>
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";
}
}
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.
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)))
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 utilisezfor..in. Vous pouvez supposer que chaque propriété deunitsapparaît dans l'itération.