88

我正在开发一个网络应用程序。

我需要正确显示一些十进制数据,以便可以将其复制并粘贴到GUI不受我控制的某个应用程序中。

GUI 应用程序是区域设置敏感的,它只接受在系统中设置的正确的小数分隔符。

我可以猜出小数点分隔符,Accept-Language并且在 95% 的情况下猜测是正确的,但有时它会失败。

有没有办法在服务器端(最好是这样我可以收集统计数据)或客户端?

更新:

任务的重点是自动完成。

事实上,这个 web 应用程序是一种传统 GUI 的在线界面,有助于正确填写表格。

使用它的用户大多不知道小数分隔符是什么。

Accept-Language解决方案已实施并且有效,但我想对其进行改进。

更新2:

我需要检索一个非常具体的设置:小数点分隔符设置在Control Panel / Regional and Language Options / Regional Options / Customize.

我处理四种操作系统:

  1. 以逗号作为 DS 的俄语 Windows (80%)。
  2. 英文 Windows,句点为 DS (15%)。
  3. 带有一段时间作为 DS 的俄语 Windows 以使编写不佳的英语应用程序正常工作 (4%)。
  4. 用逗号作为 DS 的英语 Windows 使编写不佳的俄语应用程序正常工作 (1%)。

所有 100% 的客户都在俄罗斯,遗留应用程序处理俄罗斯政府签发的表格,因此要求一个国家将产生 100% 的俄罗斯联邦,GeoIP 将产生 80% 的俄罗斯联邦和 20% 的其他国家(不正确)答案。

4

14 回答 14

135

这是一个简单的 JavaScript 函数,它将返回此信息。在 Firefox、IE6 和 IE7 中测试。在每次更改控制面板/区域和语言选项/区域选项/自定义下的设置之间,我都必须关闭并重新启动浏览器。但是,它不仅拾取了逗号和句号,还拾取了奇怪的自定义内容,例如字母“a”。

function whatDecimalSeparator() {
    var n = 1.1;
    n = n.toLocaleString().substring(1, 2);
    return n;
}

function whatDecimalSeparator() {
    var n = 1.1;
    n = n.toLocaleString().substring(1, 2);
    return n;
}

console.log('You use "' + whatDecimalSeparator() + '" as Decimal seprator');

这有帮助吗?

于 2009-08-20T19:53:00.727 回答
22

可以使用 检索当前或给定语言环境的分隔符Intl.NumberFormat#formatToParts

function getDecimalSeparator(locale) {
    const numberWithDecimalSeparator = 1.1;
    return Intl.NumberFormat(locale)
        .formatToParts(numberWithDecimalSeparator)
        .find(part => part.type === 'decimal')
        .value;
}

它仅适用于支持 Intl API 的浏览器。否则它需要一个Intl polyfill

例子:

> getDecimalSeparator()
"."
> getDecimalSeparator('fr-FR')
","

奖金:

我们可以扩展它以检索给定语言环境的小数组分隔符:

function getSeparator(locale, separatorType) {
        const numberWithGroupAndDecimalSeparator = 1000.1;
        return Intl.NumberFormat(locale)
            .formatToParts(numberWithGroupAndDecimalSeparator)
            .find(part => part.type === separatorType)
            .value;
    }

例子:

> getSeparator('en-US', 'decimal')
"."
> getSeparator('en-US', 'group')
","
> getSeparator('fr-FR', 'decimal')
","
> getSeparator('fr-FR', 'group')
" "
于 2018-07-18T21:41:17.907 回答
11

询问用户,不要猜测。在您的 Web 应用程序中对其进行设置。

编辑添加:

我认为可以猜测默认设置可以正常工作,比如 95% 的时间。我的意思是用户应该仍然能够覆盖软件所做的任何猜测。当一个软件试图变得太聪明并且不允许被纠正时,我已经多次感到沮丧。

于 2009-07-02T14:59:59.710 回答
8
function getDecimalSeparator() {
    //fallback  
       var decSep = ".";

        try {
            // this works in FF, Chrome, IE, Safari and Opera
            var sep = parseFloat(3/2).toLocaleString().substring(1,2);
            if (sep === '.' || sep === ',') {
                decSep = sep;
            }
        } catch(e){}

        return decSep;
    }
于 2014-12-12T13:23:17.227 回答
7

为什么不

console.log(0.1.toLocaleString().replace(/\d/g, ''));

于 2015-10-23T21:13:06.067 回答
5

我可以从 Accept-Language 中猜出小数点分隔符,并且猜想在 95% 的情况下是正确的,但有时它会失败。

这是 IMO 最好的做法。为了处理故障,请在显示区域旁边添加一个链接以手动设置它。

于 2009-07-02T15:13:01.463 回答
4

使用其他人的答案,我编译了以下十进制和千位分隔符实用函数:

var decimalSeparator = function() {
    return (1.1).toLocaleString().substring(1, 2);
};
var thousandSeparator = function() {
    return (1000).toLocaleString().substring(1, 2);
};

享受!

于 2017-06-01T11:06:03.017 回答
1

我认为您必须依靠 JavaScript 为您提供语言环境设置。
但显然 JS 无法直接访问这些信息。
我看到Dojo Toolkit依赖于外部数据库来查找语言环境信息,尽管它可能不考虑帐户设置更改。
我看到的另一个解决方法是使用一个小的静默 Java 小程序从系统中查询此信息,并使用 JavaScript 将其从 Java 中取出。
如果您不知道该怎么做,我可以提供更多信息(当然,如果您想走这条复杂的路线)。

[编辑] 所以我更新了我在 Java 中本地化支持的知识......
与我最初的想法不同,你不会直接使用小数分隔符或千位分隔符,就像使用行分隔符或路径分隔符一样:取而代之的是 Java提供 API 来格式化您提供的数字或日期。
不知何故,这是有道理的:在欧洲,您经常将货币符号放在数字之后,一些国家(印度?)有更复杂的规则来分隔数字等。

另一件事:Java 正确地从系统中找到当前语言环境,但不从那里获取信息(可能是出于上述原因)。相反,它使用自己的一套规则。因此,如果您有一个西班牙语语言环境,您将小数分隔符替换为感叹号,Java 将不会使用它(但也许您的应用程序也不会使用它......)。

所以我正在编写一个将服务(函数)公开给 JavaScript 的小程序,允许将数字格式化为当前语言环境。您可以使用它,使用 JavaScript 在浏览器上格式化数字。或者您可以只输入一些样本编号并从那里提取符号,在本地使用它们或将它们反馈回服务器。

我完成并测试了我的小程序并很快将其发​​布到那里。

于 2009-07-02T15:05:59.480 回答
1

即使您知道这个“GUI 应用程序”在什么语言环境下运行,您仍然需要弄清楚是如何获得当前语言环境的,以及是如何确定小数点分隔符的。

我不知道它是如何在 Mac 上完成的,但在 Windows 应用程序上应该询问通过控制面板设置的用户首选项。这个神秘的应用程序很可能会忽略这些设置,而是使用它们自己的内部设置。

或者也许他们正在采用当前的语言环境,并推断其余的,而不是被告知。

即使这样,在英语中,数字也以 3 位数字为一组给出,并用逗号分隔各组。IE:

5,197,359,078

除非数字是包含电话号码的整数:

519-735-9078

除非该数字当然是包含帐号的整数:

5197359078

在这种情况下,您将回到硬编码的覆盖逻辑。

编辑:删除货币示例,因为货币有自己的格式规则。

于 2009-07-04T20:26:57.867 回答
1

好的,我有一些东西要展示,与其说是成品,不如说是概念证明,但由于缺乏精确的规格,我就这样离开了(或者我会过度设计它)。我在单独的消息中发布,因为它会有点长。我借此机会尝试了更多 jQuery ......

Java 代码: GetLocaleInfo.java

import java.applet.*;
import java.util.Locale;
import java.text.*;

public class GetLocaleInfo extends Applet
{
  Locale loc;
  NumberFormat nf;
  NumberFormat cnf;
  NumberFormat pnf;

  // For running as plain application
  public static void main(String args[])
  {
    final Applet applet = new GetLocaleInfo();
    applet.init();
    applet.start();
  }

  public void init() // Applet is loaded
  {
    // Use current locale
    loc = Locale.getDefault();
    nf = NumberFormat.getInstance();
    cnf = NumberFormat.getCurrencyInstance();
    pnf = NumberFormat.getPercentInstance();
  }

  public void start() // Applet should start
  {
    // Following output goes to Java console
    System.out.println(GetLocaleInformation());
    System.out.println(nf.format(0.1));
    System.out.println(cnf.format(1.0));
    System.out.println(pnf.format(0.01));
  }

  public String GetLocaleInformation()
  {
    return String.format("Locale for %s: country=%s (%s / %s), lang=%s (%s / %s), variant=%s (%s)",
        loc.getDisplayName(),
        loc.getDisplayCountry(),
        loc.getCountry(),
        loc.getISO3Country(),

        loc.getDisplayLanguage(),
        loc.getLanguage(),
        loc.getISO3Language(),

        loc.getDisplayVariant(),
        loc.getVariant()
    );
  }

  public String FormatNumber(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return nf.format(value);
  }

  public String FormatCurrency(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return cnf.format(value);
  }

  public String FormatPercent(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return pnf.format(value);
  }
}

使用上述小程序的 HTML 页面示例: GetLocaleInfo.html

<!-- Header skipped for brevity -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></script>
<script type="text/javascript">
var applet;
$(document).ready(function()
{
  applet = document.getElementById('LocaleInfo');
  $('#Results').text(applet.GetLocaleInformation());
});
</script>
<script type="text/javascript">
function DoFormatting()
{
  $('table.toFormat').each(function()
  {
    var table = $(this);
    $('td', table).each(function(cellId)
    {
      var val = $(this);
      if (val.is('.number'))
      {
        val.text(applet.FormatNumber(val.text()));
      }
      else if (val.is('.currency'))
      {
        val.text(applet.FormatCurrency(val.text()));
      }
      else if (val.is('.percent'))
      {
        val.text(applet.FormatPercent(val.text()));
      }
    });
  });
}
</script>
</head>
<body>
  <div id="Container">
    <p>Page to demonstrate how JavaScript can get locale information from Java</p>
    <div id="AppletContainer">
      <object classid="java:GetLocaleInfo.class"
          type="application/x-java-applet" codetype="application/java"
          name="LocaleInfo" id="LocaleInfo" width="0" height="0">
        <param name="code" value="GetLocaleInfo"/>
        <param name="mayscript" value="true"/>
        <param name="scriptable" value="true"/>
        <p><!-- Displayed if object isn't supported -->
          <strong>This browser does not have Java enabled.</strong>
          <br>
          <a href="http://java.sun.com/products/plugin/downloads/index.html" title="Download Java plug-in">
          Get the latest Java plug-in here
          </a> (or enable Java support).
        </p>
      </object>
    </div><!-- AppletContainer -->
    <p>
    Click on the button to format the table content to the locale rules of the user.
    </p>
    <input type="button" name="DoFormatting" id="DoFormatting" value="Format the table" onclick="javascript:DoFormatting()"/>
    <div id="Results">
    </div><!-- Results -->
<table class="toFormat">
<caption>Synthetic View</caption>
<thead><tr>
<th>Name</th><th>Value</th><th>Cost</th><th>Discount</th>
</tr></thead>
<tbody>
<tr><td>Foo</td><td class="number">3.1415926</td><td class="currency">21.36</td><td class="percent">0.196</td></tr>
<tr><td>Bar</td><td class="number">159263.14</td><td class="currency">33</td><td class="percent">0.33</td></tr>
<tr><td>Baz</td><td class="number">15926</td><td class="currency">12.99</td><td class="percent">0.05</td></tr>
<tr><td>Doh</td><td class="number">0.01415926</td><td class="currency">5.1</td><td class="percent">0.1</td></tr>
</tbody>
</table>
  </div><!-- Container -->
</body>
</html>

在 Windows XP Pro SP3 上的 Firefox 3.0、IE 6、Safari 3.1 和 Opera 9.50 上测试。前两个可以正常工作,在 Safari 上我在 init() 调用后有一个奇怪的错误:

java.net.MalformedURLException: no protocol:
    at java.net.URL.<init>(Unknown Source)
    at java.net.URL.<init>(Unknown Source)
    at java.net.URL.<init>(Unknown Source)
    at sun.plugin.liveconnect.SecureInvocation.checkLiveConnectCaller(Unknown Source)
    at sun.plugin.liveconnect.SecureInvocation.access$000(Unknown Source)
    at sun.plugin.liveconnect.SecureInvocation$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.plugin.liveconnect.SecureInvocation.CallMethod(Unknown Source)

但它仍然有效。

我无法让它与 Opera 一起工作:小程序正确加载,因为我可以在 Java 控制台中看到 init() 调用的跟踪,当 JavaScript 调用 Java 函数时我没有错误(除非我添加并调用一个方法奇怪的是,获取一个 JSObject 参数),但没有调用 Java 函数(我添加了调用的跟踪)。
我相信 Liveconnect 在 Opera 中有效,但我还没有看到如何。我会多研究一点。
[更新] 我删除了对不存在的 jar 文件的引用(这不会阻止其他浏览器),我得到了调用的跟踪,但它没有更新页面。
嗯,如果我alert(applet.GetLocaleInformation());得到了信息,那么它可能是一个 jQuery 问题。

于 2009-07-07T10:20:33.583 回答
0

与其他答案类似,但压缩为常量

const decimal=.1.toLocaleString().substr(1,1);      //returns "." in Canada

此外,要获得千位分隔符

const thousands=1234..toLocaleString().substr(1,1);   //returns "," in Canada

只需将代码放在 JS 的顶部,然后根据需要调用以返回符号。


例如(我住的地方),删除逗号"1,234,567"

console.log( "1,234,567".replaceAll(thousands,"") ); //prints "1234567" to console.  
于 2020-10-31T08:15:11.500 回答
0

有没有办法在服务器端(最好是这样我可以收集统计数据)或客户端?

从服务器端。这可以通过(.NET)从系统中获取小数点分隔符

string x = CultureInfo.CurrentCulture.NumberFormat.NumberDsecimalSeparator;

剩下的工作是检查用于导出的分隔符​​,它与x 逗号 (",") 或分号 (";") 不同,以防csv导出

于 2021-08-20T07:54:23.690 回答
-1

“有什么办法可以在服务器端(最好是这样我可以收集统计数据)或客户端?”

不,你不能。该 GUI 正在查看某些用户或机器特定的设置。首先,您可能不知道此 UI 正在查看哪些设置。其次,对于 web 应用程序,您可能无法检查这些设置(客户端 --> Javacsript)。

于 2009-07-02T14:31:58.160 回答
-4

另一种可能的解决方案:您可以使用GeoIP(PHP 中的示例)之类的东西来确定用户的位置并根据这些信息做出决定。

于 2009-07-02T15:21:18.700 回答